Lorenzo Bettini is an Associate Professor in Computer Science at the Dipartimento di Statistica, Informatica, Applicazioni "Giuseppe Parenti", Università di Firenze, Italy. Previously, he was a researcher in Computer Science at Dipartimento di Informatica, Università di Torino, Italy.
He has a Masters Degree summa cum laude in Computer Science (Università di Firenze) and a PhD in "Logics and Theoretical Computer Science" (Università di Siena).
His research interests cover design, theory, and the implementation of statically typed programming languages and Domain Specific Languages.
He is also the author of about 90 research papers published in international conferences and international journals.
On some computers, such as the new DellPro Max Tower T2 and the older XPS 13, the SATA operation mode for the SSD is set to RAID by default.
Linux will not recognize the SSD in RAID mode; you need to change it to AHCI.
If you just change it to AHCI in BIOS, Windows will not boot.
The idea is to boot Windows in Safe Mode once, then change the SATA mode to AHCI in BIOS, then boot Windows normally (it will automatically load the AHCI drivers).
WARNING: Do the procedure at your own risk!
The procedure can be found in many places online.
However, I decided to put the steps that worked for me here:
Click the Start Button and type cmd; Right-click the result and select Run as administrator
Type this command and press ENTER: bcdedit /set {current} safeboot minimal (If it does not work, use this alternative: bcdedit /set safeboot minimal)
Restart the computer and enter BIOS Setup (in Dell, it is F2)
Change the SATA Operation mode to AHCI from RAID
Save changes and exit Setup, and Windows will automatically boot to Safe Mode.
Do as in the first step to open an elevated command prompt.
Type this command and press ENTER: bcdedit /deletevalue {current} safeboot (If it does not work, use this alternative: bcdedit /deletevalue safeboot)
Reboot once more, and Windows will automatically start with AHCI drivers enabled.
Note that in the Dell Pro Max Tower T2 BIOS, you must enable the “Advanced Setup” (see the top-left corner) to be able to change the operation mode in the “Storage” section:
If you’re a KDE user who wants to keep your desktop configuration under version control, you’ve probably discovered that KDE’s configuration files can be quite challenging to manage with traditional dotfile tools. KDE stores settings in complex INI files that frequently change, contain system-specific data, and include sections you may not want to track. This is where Chezmoi Modify Manager becomes useful when using the Chezmoi dotfile manager.
The Problem with KDE Configuration Files
KDE applications like Kate, Dolphin, and KWin store their settings in INI-style configuration files. These files often contain:
Volatile sections that change frequently (like window positions, recent files)
System-specific data (like file dialog sizes, screen configurations)
Mixed content where you only want to track specific settings
Things have improved recently in that respect; however, some KDE INI files still mix those configurations.
Managing these files directly with Chezmoi would result in noisy diffs and configurations that don’t work well across different machines.
Enter Chezmoi Modify Manager
Chezmoi Modify Manager acts as a configurable filter between your actual config files and your Chezmoi repository. It allows you to:
Ignore entire sections or specific keys
Set specific values while ignoring everything else
Use regex patterns for flexible matching
Transform values during processing
The tool works by creating “modify scripts” that tell Chezmoi how to process each configuration file.
For each settings file you want to manage with chezmoi_modify_manager there will be two files in your chezmoi source directory:
modify_<config file> or modify_<config file>.tmpl, e.g. modify_private_kdeglobals.tmpl
This is the modify script/configuration file that calls chezmoi_modify_manager. It contains the directives describing what to ignore.
<config file>.src.ini, e.g. private_kdeglobals.src.ini
This is the source state of the INI file.
The modify_ script is responsible for generating the new state of the file given the current state in your home directory. The modify_ script is set up to use chezmoi_modify_manager as an interpreter to do so. chezmoi_modify_manager will read the modify script to read configuration and the .src.ini file and by default will apply that file exactly (ignoring blank lines and comments).
Thus, the integration with Chezmoi is based on these mechanisms:
Source files (.src.ini) contain your desired configuration
Modify scripts (starting with modify_) define filtering rules
Chezmoi applies the modifications when deploying configs
The .chezmoiignore file ensures source files aren’t directly copied
The file name after “modify_” and the file name of the “.src.ini” must follow the naming conventions of Chezmoi.
Your .chezmoiignore must include:
1
2
**/*.src.ini
This prevents the source files from being deployed directly, letting Chezmoi Modify Manager handle the processing.
So, let’s see how to use that.
Real-World Examples
You can use the “chezmoi_modify_manager” command line to create the proper files.
Let’s look at how this works in practice with actual KDE configurations, based on my dotfiles (so I have already created these files):
KWin Configuration (kwinrc)
The file “modify_private_kwinrc”:
1
2
3
4
5
6
7
8
9
#!/usr/bin/env chezmoi_modify_manager
source auto
ignore section"$Version"
ignore section"Desktops"
ignore regex"Tiling.*"".*"
ignore section"Xwayland"
This script ensures only the relevant window manager settings are tracked (the file “private_kwinrc.src.ini”):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[Effect-cube]
CubeFaceDisplacement=126
DistanceFactor=1.82
[Effect-magiclamp]
AnimationDuration=400
[Plugins]
cubeEnabled=true
magiclampEnabled=true
squashEnabled=false
[TabBox]
DesktopMode=0
HighlightWindows=false
LayoutName=compact
Global Shortcuts (kglobalshortcutsrc)
The names of the files are using the same convention already shown before.
For keyboard shortcuts, you might want to ignore certain dynamic sections:
1
2
3
4
5
6
#!/usr/bin/env chezmoi_modify_manager
source auto
ignore section"ActivityManager"
This keeps your custom shortcuts while filtering out activity-specific bindings that may not be relevant across systems. The file “private_kglobalshortcutsrc.src.ini” is not shown because it’s quite huge.
Font Configuration (kdeglobals)
Sometimes you only want to track a single setting:
For Kate, you might want to ignore volatile sections while keeping your editor preferences:
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env chezmoi_modify_manager
source auto
ignore section"KFileDialog Settings"
ignore section"FileDialogSize"
ignore section"KTextEditor::Search"
ignore section"MainWindow"
ignore regex"Kate Print Settings.*"".*"
Again, the “.src.ini” file is not shown.
Benefits
Clean diffs: Only track settings you care about
Portable configs: No system-specific clutter
Selective tracking: Include only relevant sections
Drawbacks
In general, setting the files initially takes much more time: you need to understand what to include/exclude in the “modify_” scripts and properly craft the “.src.ini” files accordingly. Moreover, some Chezmoi mechanisms, such as “merge,” will not function. Therefore, updating the files requires employing alternative techniques, as outlined in the next blog post. Finally, besides “chezmoi”, you need to install an additional program “chezmoi_modify_manager”.
No problems on GNOME either; I’d expect that since it is “natively” based on GTK:
If I run Eclipse forcing X11 (GDK_BACKEND=x11), I see no difference.
KDE
On KDE, the situation is not bad, but I find it far from optimal.
Eclipse on Wayland doesn’t look completely native on KDE Plasma:
Many parts don’t look sized correctly.
There’s also the strange thing of the window title bar for the splash screen, which, of course, is not expected:
Dialogs also look not properly sized:
In X11, it looks better, or at least better integrated with the KDE desktop. Moreover, there’s no additional titlebar in the splash screen, and the dialog looks better (for size and width):
Unison, a powerful file synchronizer, has long been one of my favorite tools. However, installing Unison on macOS used to be a manual and sometimes cumbersome process, as detailed in my earlier guide.
The great news is that Unison is now available as a Homebrew cask! This means you can install it with a single command, leveraging the convenience and reliability of Homebrew’s package management.
To install Unison, simply run:
1
2
brew install--cask unison-app
This command will download and install the Unison application into your /Applications folder.
After installation, you might encounter permission issues due to macOS’s security features (especially if you downloaded the app from the internet). To clear any extended attributes that might prevent Unison from launching, run:
1
2
xattr-c/Applications/Unison.app
This command removes quarantine flags and ensures Unison can start without macOS warnings.
For more details and troubleshooting tips, check out my earlier guide.
I bought this laptop in late 2016. It’s still a good laptop (8 GB RAM, 128 GB SSD) and very light. However, I cannot use it with macOS anymore.
I previously blogged on installing Ubuntu on my old MacBook Air. Everything mainly went smoothly, except for the WiFi, which was not working during and after the installation, but it could be fixed by installing the proper module. The upgrade to Ubuntu 25.04 was almost fine: after the upgrade, the system did not boot anymore; I didn’t even get the Grub menu.
Ubuntu once again disappointed me. Time to wipe everything and go with my favorite Arch Linux distribution: EndeavourOS. In particular, “Mercury Neo”.
Installation
After having put the EndeavourOS ISO on a USB stick with Ventoy and inserted the USB stick, turn on the Mac and immediately press and hold the Option (⌥) key until you see the startup disk selection screen:
Select the entry corresponding to the USB and get to the Ventoy menu.
After some time, here’s the live system:
Did you notice the WiFi icon? Exactly! The WiFi has been automatically detected! Well done!
This is the WiFi card:
1
2
[liveuser@eos- ~]$ lspci -nn | grep Network
03:00.0 Network controller [0280]: Broadcom Inc. and subsidiaries BCM4360 802.11ac Dual Band Wireless Network Adapter [14e4:43a0] (rev 03)
And we can see that the corresponding kernel module is part of the live system (of course, it will also be part of the installed system):
1
2
3
[liveuser@eos- ~]$ pacman -Qs broadcom
local/broadcom-wl-dkms 6.30.223.271-42
Broadcom 802.11 Linux STA wireless driver
I changed the keyboard layout for an easier installation.
Before starting the installation, I use the Welcome menu to update Arch and EndeavourOS mirrors, of course, after connecting to the WiFi.
Before going on, everything seemed to work: touchpad, keyboard light, volume, brightness, though function keys were inverted. We’ll fix that later.
Let’s start the installation, choosing the “Online” method:
Then, the installation, based on Calamares, is the standard one, showing a few dialogs to select some configurations:
I will install KDE:
I also select as additional packages the LTS kernel and the printing packages:
As usual, I choose Grub as the bootloader:
I choose to wipe everything, select BTRFS as the file system, and also “Swap with hibernation”:
Let’s review everything and choose “Install”:
The installation takes a few minutes. Time to restart:
The installed system
Here we are:
Here are some screenshots of the good-looking KDE desktop:
And, of course, the fastfetch output in all its glory:
Configuration
As already stressed, unlike Ubuntu, there’s no need to fix any WiFi problem: it works out of the box!
Then, let’s fix the function keys, which are inverted (so, to have F1, you’d have to press “Fn F1”, which is not ideal). You can try:
Concerning hibernation (selected during the installation), it does work; however, there’s a big problem: the system does not shut down, it reboots. Upon rebooting, it effectively resumes from hibernation, but as it is, it’s rather useless. I still have not figured out how to fix that.
Another thing not working is the webcam.
This is the device:
1
2
❯ lspci -nn | grep Cam
02:00.0 Multimedia controller [0480]: Broadcom Inc. and subsidiaries 720p FaceTime HD Camera [14e4:1570]
Maybe it’s just a matter of installing the corresponding packages, but I haven’t investigated further yet.
Everything else works smoothly, as I have already said (including touchpad gestures in KDE).
Final thoughts
The laptop works great with EndeavourOS, even better than with Ubuntu. Everything is smooth and reactive. Even more than with the original old macOS operating system.
I noted that concerning sleep, the default configuration already uses the more power-saving setting:
1
2
❯cat/sys/power/mem_sleep
s2idle[deep]
Power consumption also works fine after installing the powertop package (running that with the “auto-tune” setting) and setting the power profile to “Power Saver” from the KDE menu. MacOS probably used to have better power consumption, but this one is acceptable.
It was a nice decision to put Linux on this laptop, even more so with EndeavourOS instead of Ubuntu! 🙂
Zram, https://www.kernel.org/doc/html/latest/admin-guide/blockdev/zram.html, is a Linux kernel module that creates a compressed block device in RAM. This device can be used as swap space or a general-purpose RAM disk. By compressing data in memory, zram allows your system to store more data in RAM, reducing the need to swap to slower disk storage and improving overall responsiveness.
In particular, zram
Increases effective RAM capacity by compressing data.
Reduces disk I/O and wear, especially useful on SSDs.
Improves performance on systems with limited memory.
If you’re looking to boost your Linux system’s performance, especially on machines with limited RAM, zram is a powerful tool worth exploring.
In this post, I’ll show how to set it up on both Arch Linux and Ubuntu.
Installing zram
On Arch Linux
Install the zram generator package:
1
2
sudo pacman-Szram-generator
On Ubuntu
Install the systemd zram generator:
1
2
sudo apt install systemd-zram-generator
Configuring zram
Create a configuration file to set up your zram device. For example, to allocate half of your system’s RAM to zram and use the efficient zstd compression algorithm, run:
I like Nerd Fonts a lot, and blogged about those in the past. If you spend a lot of time in the terminal, you’ve probably heard of them: they patch popular programming fonts with a huge set of icons, making your terminal and development environment look great and more informative.
Here’s how you can easily install Nerd Fonts on macOS using Homebrew.
Step 1: Install Homebrew (if you haven’t already)
If you don’t have Homebrew installed, open your terminal and run:
Before installing fonts, it’s a good idea to have fontconfig:
1
2
brew install fontconfig
Step 3: Install Nerd Fonts with Homebrew Cask
Homebrew makes it easy to install fonts with the --cask option. Here’s how I install my favorite Nerd Fonts:
1
2
3
4
5
6
brew install--cask\
font-jetbrains-mono-nerd-font\
font-caskaydia-cove-nerd-font\
font-iosevka-term-nerd-font\
font-fira-mono-nerd-font
You can add or remove fonts from this list as you prefer. Homebrew will handle downloading and installing them for you.
Step 4: Use Your New Fonts
After installation, open your terminal or code editor’s settings and select your preferred Nerd Font from the font list. Now you can enjoy enhanced icons and a better coding experience!
Tip: You can browse all available Nerd Fonts with:
In this blog post, I’ll document how to use delta: a syntax-highlighting pager for git, diff, and grep output.
Delta makes diffs much more readable by adding syntax highlighting, line numbers, and custom themes. This is especially helpful when reviewing changes in Lazygit, as it makes it easier to spot what’s changed at a glance.
Installing delta
On Arch Linux (or derivatives), you can install delta with:
When working with Maven projects, the Surefire plugin is commonly used to execute tests, but it lacks a built-in feature to display the total execution time across all test suites. This can be particularly important when monitoring performance trends in larger projects with many test classes.
Maven’s Surefire plugin reports execution time for individual test classes but doesn’t provide an aggregated view of the total test execution time. The reports are generated in the “target/surefire-reports” folder, both as text files and XML files.
Here’s a shell script that parses the XML report files generated by Surefire and calculates the total execution time. The script is compatible with both Linux and macOS environments.
Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
# Calculate total test execution time by summing only the time attributes from the testsuite elements
# Using a more compatible awk syntax for macOS and other platforms
For each matching line, loops through all fields (words) in the line
Find fields that start with time=
Uses gsub() to extract just the numeric value by removing the time=" prefix and the " suffix
Add the extracted value to the running total
Format the output in the same way, with the total time in seconds
To make this script run automatically after your tests, you can integrate it into your Maven build process using the exec-maven-plugin:
XHTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<id>extract-total-test-time</id>
<phase>test</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>bash</executable>
<arguments>
<argument>report-total-time.sh</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
The above snippet assumes the script is in a file “report-total-time.sh” in the same directory as the POM. Otherwise, you’ll have to adjust the argument accordingly.
When your tests complete, you’ll see output similar to:
The Gitpod custom Dockerfile, “.gitpod.Dockerfile”, must be tweaked to install Neovim and its requirements (especially for using Lazyvim):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# You can find the new timestamped tags here: https://hub.docker.com/r/gitpod/workspace-full/tags
FROM gitpod/workspace-full:2025-04-16-08-49-20
# Install packages that are not in the Ubuntu repos
# the version in Ubuntu repos is too old for lazy.vim
# shellcheck is not available at all in Ubuntu repos
RUN brew update
RUN brew install \
neovim \
shellcheck
# install-packages is a wrapper for `apt` that helps skip a few commands in the docker env.
# additional packages needed in neovim with this configuration
# (tree is just to inspect folders, not needed by neovim)
RUN sudo install-packages \
fzf \
ripgrep \
stow \
npm \
tree
Then, the file “.gitpod.yml” must be tweaked accordingly; in particular, I’m using “stow” to create a symlink for the default Neovim configuration directory using as the source the configuration directory of this repository (you could also simply use the “ln” command for that):
YAML
1
2
3
4
5
6
7
8
9
10
image:
file: .gitpod.Dockerfile
tasks:
- init: ./stow.sh
vscode:
extensions:
-ms-azuretools.vscode-docker
-eamodio.gitlens
The “stow.sh” script is part of the repository. I also specify a few extensions to install in the VScode of Gitpod.
Note that the first time, it will take a few minutes for Gitpod to provision such a Docker image.
Once in Gitpod, we can see that the link has been already configured:
Now, let’s enlarge the Terminal view and start Neovim.
We should see Neovim is installing all the packages as configured by LazyVim:
Note the change of the default color scheme:
Let’s close the Lazy window and see the Dashboard:
Since I’m using a light theme for the VScode, upon restarting Neovim, the color scheme is changed to its light variant as well:
We can now open the explorer (“space e”) to browse the contents:
By default, we have the Lua LSP installed.
We can use the file picker (“space f”):
We can use Lua LSP features like code completion:
And hover (“K”):
And change the color scheme with the picker (“space u C”):
Note that there are a few things that are not working correctly in Gitpod concerning Neovim:
Clipboard does not work since there’s no “DISPLAY” set.
Missing nerd fonts, things like folders and file types in the explorer, are not rendered correctly.
Using “pip” is the supported installation method for Ansible and Molecule. Let’s install Python libraries and applications (in this case, Ansible and Molecule) in a Python virtual environment. (This post is similar to the one about Ubuntu.)
First, install the required packages, including the Python virtual environment package:
Shell
1
sudo pacman-Spython-pip python-virtualenv
Create a virtual environment somewhere (in this example, I create it in my home folder as a subdirectory of a folder for all the virtual environments; the directory will be created automatically):
Shell
1
python-mvenv~/.venv/molecule
Once the virtual environment has been created, “enter” the virtual environment:
Shell
1
source~/.venv/molecule/bin/activate
Install the Python packages for Ansible, Molecule, and its plugins in the virtual environment:
I experimented with Copilot “Agent mode”: I told it to create a Maven plugin. (Let me stress that I already have some experience implementing and testing Maven plugins.)
I’ll report my experience, which has been positive in some respects but disappointing in others.
I use “Claude 3.5 Sonnet” model because that’s the one used in most demos I saw online.
This is the initial prompt:
I want to create a Maven plugin, using the official archetype.
The groupId for the project must be “com.examples” and the artifactId must be “exampleplugin”.
The project must be part of a Git repository, with the standard .gitignore file (excluding typical generated artifacts of a Maven project and also other typical files that must be excluded, including OS typical generated files).
The project must be up-to-date with respect to dependencies and plugins, and it must use Java 21.
I want also to use the Maven wrapper in this project, using the latest version of Maven (but not Maven 4).
I also want the GitHub Actions workflow to build and test the project (including integration tests) for Linux, Windows and macOS.
Is everything clear? Do you have any question?
Here’s the first output, which correctly uses the command for the archetype:
Let’s continue and see how it goes:
The “.gitignore” ignores too many things: I want to keep Eclipse metadata files and directories.
So, before going on, I specify
The dot files for project’s metadata of the Java LSP must not be ignored (e.g., .classpath, .project, etc.); .vscode must not be ignored either
And the updated version looks right:
Then, it goes on updating versions and Java version; it also runs the command for the Maven wrapper:
It creates the GitHub Actions workflow and initializes the Git repository:
That’s the summary:
However, I’m not happy with the results.
It only updated the Java and Maven versions, but not the dependencies or plugin versions. The Maven wrapper is installed with version 3.9.6, but the latest version of Maven is 3.9.9.
The GitHub Actions workflow is not perfect either:
YAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
name: Build and Test
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest,windows-latest,macos-latest]
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: 'maven'
- name: Build and test with Maven
run: ./mvnw clean verify
- name: Run integration tests
run: ./mvnw clean verify -Prun-its
It only considers the “main” branch, and there’s no need to run two builds. However, it correctly detected the profile “run-its” for integration tests!
I then wrote this:
The tasks were almost correct.
There are a few things that must be fixed:
– The latest version of Maven (both in the POM and in the wrapper) is not 3.9.6: it is 3.9.9.
– The GitHub Actions workflow only considers the “main” branch (both for push and pr); this is not what I asked: I want to build any branch. Moreover, there’s no need to run Maven twice (as long as integration tests are run).
– Moreover, I asked to update all dependencies and plugins to their latest versions, but that’s not what happened.
As a result, the GitHub Actions workflow was fixed according to my requests.
It also updates the Maven wrapper version and verifies the correct changes in the properties file.
It also updates a few versions in the POM, reporting:
However, most of the dependencies and plugins are NOT up-to-date at all.
I then wrote:
Please, double check the dependencies and plugins: you have updated them, but some of them are not yet at the latest version.
It seems to understand that it can use the Maven versions plugin to display the dependency updates:
After running the command, it complains it cannot read the updates from the output (which, instead, are there) and tries to use another command (which is completely wrong):
I told it about the visible versions:
The versions were actually visible in the output.
And here’s the result:
Unfortunately, when it uses such information to update the POM, it makes a small disaster: most dependencies are not correctly updated, and some versions don’t exist.
I told it about that, in particular, instead of displaying updates, it could have used the proper goal of the Maven versions plugin:
Some versions are still not up-to-date, not to mention that there’s also a wrong version that cannot be resolved. Why don’t you simply use the Maven versions plugin to update dependencies and plugins instead of just displaying their output and parsing it?
But it insists on displaying and trying to change the versions (without succeeding).
So I tried to be clearer:
That only displays the latest versions and then you’ll have to parse the output, which did not work yet. Isn’t there a specific goal to also update automatically all the dependencies and plugins?
Now it understands and uses the proper goal:
It then detects that some previously updated versions were wrong, and that there are beta versions of some dependencies and plugins; the run Maven command has already updated the POM, but it insists on rechecking the versions:
Updating some versions prevents the test from being compiled anymore. Copilot did not realize that. I make it explicit:
The test file contains a compilation error. I guess you updated the corresponding dependency to a too much high version (beta version). It’s better not to use beta versions and instead use the latest version before the beta one.
Now, it starts iterating, trying to downgrade some versions. It performs several iterations and asks whether it should continue. I say yes, and at some point, it seems to make the test compile again, but looking at the versions in the POM, it looks like it almost randomly decreased versions too much. Note that, by looking at the Maven central repository, it is easy to take the latest dependency version or a plugin that does not contain “beta”.
Anyway, after the test is finally compiled again, it decides to run the Maven build to see whether everything works. That’s the first time Copilot proposes to run the Maven build (I would have expected that to be done after creating the files with the first prompt).
Here comes trouble:
The test fails (Google Guice fails when using dependency injection). It looks like Copilot understands there’s a misalignment with dependencies. In particular, trying to fix the previous compilation error, it wrongly added additional transitive dependencies (uselessly) with wrong versions, leading to this failure.
It then starts several iterations without being able to fix the test.
Ultimately, I had to revert the changes to the POM: all the previous iterations about version updates were useless and disruptive.
In the end, I was impressed by the first iterations where Copilot took most tasks correctly.
However, it clearly cannot handle tasks like version updates or compilation failures (at least, without breaking tests afterwards).
I managed to guide it in some parts because, as I said at the beginning, I know how to implement and test Maven plugins. Without such an existing experience, I had to give up very soon.
After all, this was just an experiment. Bootstrapping the project and the Git repository manually with the archetype, updating a few initial versions, and creating the GitHub Actions workflow would have taken me only a few minutes: much less than the time I spent with Copilot 😉
Maybe the “Claude 3.5 Sonnet” model was not the right one? As I said, I saw this is used in most online demos for Copilot agent mode.
The “remote” feature of flash.nvim is handy: it acts in “operator pending mode” to perform operations and then return to the original position. It took me some time to understand what it was doing, so I’m writing about it.
I’m using it in the LazyVim distribution, which enables “flash” by default (and also “which-key”, which is the window showing possible commands to complete the sequence).
Let’s take this buffer (note the current position of the cursor):
Let’s assume I want to copy (“yank”) the line containing “the very first…”. I press “y”, which goes into “operator pending mode”:
Then “r” for “remote flash”, and start typing something in that line, e.g., “location”; I type “l”,
Labels appear in the occurrences (remember that with “flash”, you should look at the word you want to jump to while you’re typing); in this example, a single letter allows you to have useful labels for jumping to the desired occurrence. You might need to type a few more letters in more complex files. I press the label corresponding to the occurrence of “location” in the interested line (“h”)
The cursor temporarily goes to the desired occurrence of “location”; then, I press “a” for around:
Finally, “p” for “paragraph”. Now the desired line has been yanked, and the cursor automatically goes back to the original position:
I could then paste the line there, for example.
Let’s see another example with “d” for deleting a remote line.
Let’s see the starting point, in particular, the current cursor position on line 18:
Let’s say I want to delete the word “very” a few lines above.
I enter “operator pending mode” with “d”
Then “r” for “remote flash”, and start typing “very”; I type “v”,
Labels appear in the occurrences (remember that with “flash”, you should look at the word you want to jump to while you’re typing), and press the label corresponding to the occurrence of “very” in the interested line (“d” in this case)
The cursor temporarily goes to the desired occurrence of “very”; then, I press “a” for around:
Finally, “w” for word. The “very” word is removed, and the cursor automatically goes back to the original position:
Try to do the same with “c” for change, to change something in a “remote” location and automatically return to where you were.
Using “pip” is the supported installation method for Ansible and Molecule. In Ubuntu, just using “pip” will lead to the error “externally-managed-environment” because of the Python environment that is “externally managed” by the package manager (this prevents direct use of pip for system-wide installations to avoid conflicts or issues).
Create a virtual environment somewhere (in this example, I create it in my home folder as a subdirectory of a folder for all the virtual environments; the directory will be created automatically):
Shell
1
python3-mvenv~/.venv/molecule
Once the virtual environment has been created, “enter” the virtual environment:
Shell
1
source~/.venv/molecule/bin/activate
Install the Python packages for Ansible, Molecule, and its plugins in the virtual environment:
This is the first part of a few tutorials on using the LaTeX typesetting system with Neovim using the LazyVim setup. I highly recommend LazyVim because it has many cool plugins configured with nice defaults. Moreover, as we see in this tutorial, it lets you quickly have VimTeX and the TexLab LSP up and running in Neovim.
You can follow this step-by-step tutorial by implementing the steps starting from a fresh LazyVim installation (see http://www.lazyvim.org/installation). If you already use LazyVim, you might want to do the steps in this tutorial on a fresh, separate Neovim configuration directory before applying all the configurations in your daily-driver Neovim configuration.
For example, if you start with the starter project provided by LazyVim, you can clone it into a separate configuration directory:
And then you start Neovim pointing to that configuration:
Shell
1
NVIM_APPNAME=lazyvim-tex nvim
This way, your existing Neovim configuration won’t be touched, and you’ll be free to experiment with this new configuration.
In these tutorials, the path is always intended relative to the Neovim configuration path when referring to a configuration file. If you follow the above commands, for example, it will be relative to “~/.config/lazyvim-tex”.
I suggest you follow the tutorials by manually executing the configuration steps in a new, separate Neovim configuration.
The final result of this series of tutorials can be found here: https://github.com/LorenzoBettini/lazyvim-tex. Branches will denote the state of the repository according to a specific blog post part.
A few initial notes
The plugin VimTeX needs a LaTeX installation and a compiler; the default is “latexmk”.
In Arch Linux, you can install it like this:
1
sudo pacman-Stexlive-binextra
You must also ensure a working LaTeX installation with all the needed packages.
I’ll use Zathura and Sioyek as PDF viewers, automatically providing bi-directional linking (synchronization) between the LaTeX sources and the PDF.
In Arch Linux, you can install Zathura like this:
1
sudo pacman-Szathura-pdf-poppler
For Sioyek, AUR packages are available.
I’ll use a light theme (“catpuccin-latte”) for Neovim instead of the default dark one in the screenshots.
The “localleader” will be remapped to “\”: VimTeX commands start with “l” and in LazyVim “<leader> l” (that is, “<space> l” is already mapped to “Lazy” commands). This remap is done automatically by the LazyVim “Tex Extra” I’ll use.
Let’s open this file with the fresh Neovim distribution.
Let’s install the LazyVim “Tex Extra”. A LazyVim extra is meant to configure several plugins and configurations with a single mechanism. In this case, it will configure VimTex, the TexLab LSP, and other related plugins and keybindings.
You have some alternatives to enable an “Extra”, which is documented for each available “Extra”; for Java, see http://www.lazyvim.org/extras/lang/tex. I prefer to use the UI: Type “:LazyExtras” to show the LazyVim Extras UI:
The LazyExtras UI proposes some recommended extras based on the files you’ve just opened, so it should recommend “lang.tex”; if not, search for “lang.tex” and when you’re on that line, press “x” to install the extra.
You get the feedback about restarting Neovim so that VimTeX is installed.
Specifying an extra as we’ve just done creates a file in the configuration, “lazyvim.json”, with this content (the numbers for news and version might be different depending on when you follow this tutorial):
Lua
1
2
3
4
5
6
7
8
9
{
"extras":[
"lazyvim.plugins.extras.lang.tex"
],
"news":{
"NEWS.md":"..."
},
"version":...
}
The idea is to keep this file in the Git repository for your configuration as part of your dotfiles for Neovim.
Once you reopen the LaTeX file, you should get feedback about Mason downloading the “texlab” LSP; this is done only the first time.
Of course, you could force the installation of “texlab” beforehand by using the Mason UI, “:Mason”: select “texlab” and install it.
Alternatively, if you want a fully automated solution that, besides installing all the Neovim plugins, also automatically installs the TeXLab LSP, you can add this Lua specification in the Neovim configuration folder (the name does not matter; I call it “extend-lsp” to stress that it extends the Mason configuration of LazyVim, https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/plugins/lsp/init.lua) “lua/plugins/extend-lsp.lua” with this content:
Lua
1
2
3
4
5
6
7
8
return{
"williamboman/mason.nvim",
opts={
ensure_installed={
"texlab",
},
},
}
Now, when you start Neovim, “texlab” will automatically install. You might want to check whether Mason has successfully downloaded and installed it or is still installing it through the Mason UI.
You can now try to edit the file using the content assist, providing completions and possible templates:
Let’s explore VimTex commands; remember that we’ll use “\” as the “localleader”. Which-key will show the available keybindings:
Let’s compile the LaTeX file with “\ l l”. This will start the compilation, which, depending on the size and complexity of the LaTeX document, takes a few seconds.
In the end, if there are no compilation errors, it automatically opens the default PDF viewer (I’m on KDE, and the default PDF viewer is Okular):
With “\ l l” we instructed VimTeX to watch for file changes (you can stop it with “\ l k”). VimTeX will automatically retrigger compilation and update the PDF document in the viewer as soon as we change the file and save it. For example, let’s add a sentence, save, and when we get feedback about the completed compilation, we should see the result in the PDF viewer:
Let’s add a LaTeX error, save, and get the list of reported errors (selecting any error will lead to the corresponding line in the source file):
Configure the PDF viewer
Let’s configure Zathura as the viewer.
Let’s add this line in the file “lua/config/options.lua”:
Lua
1
vim.g.vimtex_view_method="zathura_simple"
I’m using “zathura_simple” instead of “Zathura” because, as documented, the latter requires “xdotool”, which I don’t have. This way, we avoid the warning “Viewer cannot find Zathura window ID!”.
Let’s restart Neovim, reopen the LaTeX file, and select “\ l l”.
Now, it will open Zathura with the highlighted part corresponding to the cursor’s current position in the source file!
Let’s move the cursor in the source file to another line and press “\ l v”: the selection in the PDF is updated accordingly:
The other way round also works: from Zathura, use “Ctrl + click”, and the cursor in the source file will be updated to the corresponding line (in the screenshot below, I did “Ctrl + click” on the part of “toggles between”):
This synchronization is super useful when writing in LaTeX, isn’t it? 🙂
Alternatively, I also use Sioyek as a PDF viewer, which works on macOS as well. In this case, the option for the viewer must be changed accordingly:
Lua
1
vim.g.vimtex_view_method="sioyek"
In Sioyek, to return to the source file, enter “synctex” mode with “F4” and right-click with the mouse.
Other features
Let’s open the “Table of Contents” window with “\ l t”:
Note the helpful help contents and the “TODO” elements that were also reported.
Stay tuned for more blog posts on LaTeX and Neovim! 🙂
Similar to what I had already shown in a previous post, in this post, I show how you can install (and keep up-to-date) the “tpm” (Tmux Plugin Manager) with Chezmoi, which I highly recommend!
Typically, you manually install “tpm” by cloning its GitHub repository into the proper directory:
Chezmoi offers mechanisms for such situations: https://www.chezmoi.io/user-guide/include-files-from-elsewhere/. In particular, I use “Include a subdirectory from a git repository”: this way, Chezmoi will clone the external Git repository on the first run and will keep it up to date (i.e., “git pull”) at some specified intervals (remember, the default interval is 0!).
You need to create the file “.chezmoiexternal.toml” in the root folder of your Chezmoi file and follow the syntax in the documentation.
Here’s what I need to install “tpm” by cloning its GitHub repository:
INI
1
2
3
4
[".tmux/plugins/tpm"]
type="git-repo"
url="https://github.com/tmux-plugins/tpm"
refreshPeriod="1h"
Note that I specified a 1-hour refresh interval. Thus, if I issue a “chezmoi update”, it will keep that interval into consideration when deciding whether to check for updates (i.e., “pull”) in the Git repository. However, you also have this option in Chezmoi to force the Git update:
Let’s put Ubuntu Linux on the laptop! I’ll write the installation instructions and the configurations for a fully functional Ubuntu on this MacBook Air, which runs fast and smoothly and brings the laptop back to life!
Although I am a big fan of Arch and EndeavourOS, I first decided to try Ubuntu on this MacBook. Maybe, in the future, I’ll also try using an Arch distribution.
Installation
After having put the Ubuntu 24.10 ISO on a USB stick with Ventoy and inserted the USB stick, Turn on the Mac and immediately press and hold the Option (⌥) key until you see the startup disk selection screen:
Select the entry corresponding to the USB and get to Ventoy menu:
After some time, you should see the familiar Ubuntu splash screen:
Unfortunately, when I got to the desktop, I discovered the WiFi card had not been detected.
I’ll fix that later, after the installation.
I can use my mobile phone: I enabled USB tethering after connecting the phone with a USB cable. USB tethering in Linux works like a charm. I can now go on with the installation with a working Internet connection!
The installation is the standard Ubuntu installation:
Since I don’t want to keep any macOS installation (the space on the SSD wouldn’t be enough anyway), I choose to wipe the entire disk and let Ubuntu select a standard partition scheme.
The installer correctly detected my time zone:
Let’s start the installation, which only takes a few minutes (even considering I’m using my mobile phone connection).
By clicking the terminal icon on the bottom right, you can see the logging of the installation:
Time to restart the installed system!
Configuration
Let’s start fixing the WiFi problem.
This is the WiFi card on the laptop:
Shell
1
2
$lspci-nn|grepNetwork
03:00.0Network controller[0280]:Broadcom Inc.andsubsidiaries BCM4360802.11acDual Band Wireless Network Adapter[14e4:43a0](rev03)
I have already blogged about Thunderbird and Firefox snap packages, which I don’t like, and how to get back to dep packages.
Final thoughts
As I had already anticipated, the laptop works great with Ubuntu. Everything is smooth and reactive. Even more than with the original old macOS operating system.
I noted that concerning sleep, the default configuration already uses the more power save setting:
1
2
❯cat/sys/power/mem_sleep
s2idle[deep]
Everything else works great, including all the volume and screen brightness function keys. Moreover, the screen light automatically adjusts depending on the environment illumination!
Power consumption also works fine after installing the powertop package (running that with the “auto-tune” setting) and setting the power profile to “Power Saver” from the Gnome menu:
MacOS probably used to have better power consumption, but this one is acceptable.
It was a nice decision to put Linux on this laptop! 🙂
I like the tracker service in Gnome, which indexes files so that you can easily search for them from the Activity view or the file manager. However, I don’t like tracker-extract, which also indexes the file contents: I use Recoll for such a service, and tracker-extract uses too much CPU (it indexes new or modified files as you create/change them).
In the past, up to Gnome 45, I could disable tracker-extract only with
Things have changed again in Gnome 47 (fortunately, they haven’t changed again in Gnome 48) because the directory is now named “/usr/share/localsearch3/extract-rules/“. Thus, the removal must be done like this:
1
sudo rm/usr/share/localsearch3/extract-rules/*
If you want to keep a backup, you might want to move those files somewhere.
This is the script I’m using:
it works also in Gnome 46 (with the old directory name)
echo"localsearch3 does not exist, continuing...")&&
sudochown-R${USER}:${USER}~/tmp/extract-rules
That works!
WARNING: as soon as tracker-extract is updated to a new version, those files will show up again, and you’ll have to remove them. Possibly, before logging into Gnome, to avoid that tracker-extract starts eating your CPU.
I like it a lot! Everything seems much more readable.
See, for example, Nautilus (I’m using a different icon theme, but the font is the default one):
Also, the monospace version of Adwaita looks nice:
To better see the difference, here’s a screenshot with the old fonts:
And here’s one with the new Adwaita fonts:
Besides other new features you might find in many articles, I also appreciate that the default image viewer now provides some basic editing features (note the toolbar icon):
At least, the editing operation I use most, “cropping”, is there. Changing the size is not yet possible. That’s why I also use Gwenview in GNOME.
I immediately tried that in one of my Java projects.
Use the “Market Place” to install Copilot in Eclipse:
Once you click install, you must “trust” the contents to be installed:
Once installed and restarted Eclipse, you must authenticate with your GitHub Copilot account by clicking on the Copilot icon in the bottom right:
This will open a dialog with a code you must insert in the opened web page. Note the button to automatically copy the code in the clipboard and open the browser:
In the browser, you’ll have to authenticate in your GitHub account and paste that code (which should be in the clipboard). If everything goes fine, the webpage will tell you that everything is in place to start using Copilot in Eclipse, and Eclipse should show the corresponding success dialog:
I started to do some experiments.
I have this test code where Eclipse shows a warning on the “FileOutputStream” because the resource is not closed. Of course, I know how to solve that: use a try-with-resource block. But let’s ask Copilot.
I opened the file and the Copilot chat (still using the button in the bottom right toolbar):
Here’s what I asked:
I experienced a possible UX design problem here: I didn’t see any answer. I had to enlarge the view to see where Copilot wrote the answer (note in the same part where I wrote the question):
The answer is wrong: that is not the cause of the warning, and that is not the solution.
I tried to be more explicit in the question, detailing the message of the warning:
OK, this time, the answer is correct!
I tried to use the toolbar button to insert the solution in the editor:
However, instead of replacing the interested part, it just inserted that code starting from the editor’s cursor: a disaster of course 😉
Instead of manually copying and pasting the solution, I experimented with Copilot code completion. As I said, I know that I must use a try-with-resource. I converted the lambda expression into a block and typed “try (“. The grey code is suggested by Copilot:
I don’t know whether this is due to the selected solution in the chat or to my previous question, but the proposed code is correct! Press TAB to accept that. Then, I manually removed the duplicate original line. Maybe the original line has been used to propose the correct completion.
For the other part in the same file with the same warning, the completion was done in two steps: I started typing as before, accepted the initial partial condition, went on typing some more, and got the rest of the correct completion:
I also tried asking how to move the Maven project to Java 21 by opening the POM and using the chat:
The answer is correct, but honestly, the question was relatively trivial 😉
Unfortunately, Copilot code completion in the POM file does not work well: it tends to interfere with the default content assist in the POM; I haven’t found a way to use that properly.
Other valid key bindings:
Ctrl + Alt + / to manually trigger Copilot’s code completion;
Ctrl + Right to accept the next word in a suggestion.
Let’s see for future updates 🙂
In the meantime, I’ll try to experiment with that further.
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept All”, you consent to the use of ALL the cookies. However, you may visit "Cookie Settings" to provide a controlled consent.
This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. These cookies ensure basic functionalities and security features of the website, anonymously.
Cookie
Duration
Description
cookielawinfo-checkbox-analytics
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional
11 months
The cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
viewed_cookie_policy
11 months
The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.
Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.
Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.