Major mode in Emacs for Avalonia

Recently, I’ve been experimenting with Avalonia for GUI applications in C#. However, I found out that despite the good support for C# in Emacs, the same could not be said for Avalonia. The problem stems mostly from the fact that Avalonia uses Avalonia XAML (.axaml) files for describing the UI, which Emacs doesn’t have a mode for. Unfortunately, Avalonia doesn’t have a free LSP lying around, so I can’t really create an lsp-mode client without creating my own LSP server. However, it turns out that creating a major mode for Avalonia is really easy!

Creating a new major mode

Major modes in Emacs are really easy to create, since they are essentially just one Elisp file containing your customizations to an existing mode. The only blocker that I experienced was finding out how to get my major mode into Doom Emacs.

The first step to creating a major mode is of course, to write it. I created a directory to serve as my repository and wrote avalonia-xaml-mode.el.

1
2
3
4
5
6
7
8
(define-derived-mode avalonia-xaml-mode
nxml-mode
"Avalonia XAML"
"Major mode for editing Avalonia XAML.")

(add-to-list 'auto-mode-alist '("\\.axaml\\'" . avalonia-xaml-mode))

(provide 'avalonia-xaml-mode)

define-derived-mode creates a new mode called avalonia-xaml-mode, basing the mode from Emacs’ existing nxml-mode to provide syntax highlighting. The two string arguments are just the text to display on the mode line and the docstring of the mode.

Next, we call add-to-list to associate the .axaml file extension with the mode.
Finally, we provide the mode itself.
After writing the code, we need to upload it to a Git repository. The Git repo must be named with the same name as the file containing the mode, so I named the repo avalonia-xaml-mode. Afterwards, I pushed the repository to the remote with the branch master, since this is the branch most Emacs package managers use by default when getting packages from Git repos.

After pushing the changes to the remote, I can now install it in Doom Emacs by writing the following in packages.el

1
2
3
(package! avalonia-xaml-mode
:recipe (:host codeberg
:repo "jhgalino/avalonia-xaml-mode"))