Hello, everyone! I am looking for a way to highlight code snippets inside Nix strings. I use VS Code and Neovim for editing text.
Using proprietary Nix syntax or sourcing files is not an option for me. The proprietary Nix syntax will compromise the formatting, making the configuration files less readable in a non-Nix-based environment, while sourcing files means missing out on the Nix constants and other functionality. Both of these points are deal breakers for me.
Here is a snippet from my configuration for Waybar:
style = lib.concatStrings [
''
/* some styles here */
window#waybar > box {
background-color: rgba(${base00RGB}, 0.6);
border-radius: 0px;
color: #${base00};
box-shadow: 0px 2px 5px 0px rgba(${base00RGB}, 0.6);
}
/* some other styles here */
''
];
I want the code inside the string to be properly highlighted. What are some ways I can do that in VS Code and Neovim?
Best way to do this is just to have those files in a separate file and read them to strings with builtins.readFile. That gives you syntax highlighting, formatting, linting, etc.
There are some fancy plugins for older editors (e.g. polymode for emacs), but generally they end up interfering with various bits of functionality.
In theory language servers can support this kind of thing, but none of the nix language servers currently implement this - it would be kind of difficult to, since we embed so many different languages, and there’s no good way to identify them. They’re also often snippets that lack surrounding boilerplate.
As far as I understand, this means I’ll have to miss out on the Nix functionality within that file? For example, declaring a constant using the let ... in syntax to use it inside the configuration? Or am I missing something?
Partially. You won’t be able to use nix’ string interpolation, but you can always use environment variables or the substitute helpers to push those values into the files anyway.
My personal preference is to do that for larger bits of configuration where syntax highlighting really helps, but I’m content with treating smaller snippets as text.
Good multi-language support in language servers (and git forges) would be awesome long-term, though.
For the reference: Some time ago, I compared some Emacs major/minor modes doing the same thing:
mmm-mode: Established solution. Seems to be a bit aging.
polymode: Allows definition of a host and several inner modes. Seems to
be a bit hard to set up, and the default modes do not cover my use cases.
string-edit: Offers string-edit-at-point which opens a new buffer in a
desired major mode and unescaped contents. Finishing the edit, escapes the
buffer contents and replaces the string in the original buffer.
edit-indirect: Edit regions in separate buffers. Similar to string-edit;
used by markdown-mode, and so I have it installed. I use edit-indirect
regularly, but automatic mode detection does not work well.