vscode: convert template to Nix and refactor module

Benefits:

- No need to run Mustache, so better performance
- Allows the code to be linted and formatted
- Generated file is minified
- Can use arbitrary variables to name colors and group settings
  (although this is not implemented)

Drawbacks:

- Update script is more complex

I opted to change the sorting to alphabetical order because it's
easier to implement in the update script. The script prints a list
of added and removed options, so ordering to match the upstream
documentation is not necessary.
This commit is contained in:
Daniel Thwaites 2025-03-12 17:19:43 +00:00
parent e28bd4de28
commit c5558f7de9
No known key found for this signature in database
GPG key ID: D8AFC4BF05670F9D
5 changed files with 1412 additions and 1561 deletions

View file

@ -3,35 +3,40 @@
config,
lib,
...
}:
}@args:
with config.stylix.fonts;
let
themeFile = config.lib.stylix.colors {
template = ./template.mustache;
extension = ".json";
};
themeExtension =
extension =
pkgs.runCommandLocal "stylix-vscode"
{
vscodeExtUniqueId = "stylix.stylix";
vscodeExtPublisher = "stylix";
version = "0.0.0";
theme = builtins.toJSON (import ./templates/theme.nix args);
passAsFile = [ "theme" ];
}
''
mkdir -p "$out/share/vscode/extensions/$vscodeExtUniqueId/themes"
ln -s ${./package.json} "$out/share/vscode/extensions/$vscodeExtUniqueId/package.json"
ln -s ${themeFile} "$out/share/vscode/extensions/$vscodeExtUniqueId/themes/stylix.json"
cp "$themePath" "$out/share/vscode/extensions/$vscodeExtUniqueId/themes/stylix.json"
'';
settings = import ./templates/settings.nix args;
profile = {
extensions = [ extension ];
userSettings = settings;
};
cfg = config.stylix.targets.vscode;
in
{
options.stylix.targets.vscode = {
enable = config.lib.stylix.mkEnableTarget "VSCode" true;
profileNames = lib.mkOption {
description = "The VSCode profile names to apply styling on.";
type = lib.types.listOf lib.types.str;
@ -40,44 +45,10 @@ in
};
config = lib.mkIf (config.stylix.enable && cfg.enable) {
programs.vscode.profiles = lib.mkMerge (
map (profileName: {
${profileName} = {
extensions = [ themeExtension ];
userSettings = {
"workbench.colorTheme" = "Stylix";
"editor.fontFamily" = monospace.name;
"editor.inlayHints.fontFamily" = monospace.name;
"editor.inlineSuggest.fontFamily" = monospace.name;
"scm.inputFontFamily" = monospace.name;
"debug.console.fontFamily" = monospace.name;
"markdown.preview.fontFamily" = sansSerif.name;
"chat.editor.fontFamily" = monospace.name;
programs.vscode.profiles = lib.genAttrs cfg.profileNames (_name: profile);
# 4/3 factor used for pt to px;
"editor.fontSize" = sizes.terminal * 4.0 / 3.0;
"debug.console.fontSize" = sizes.terminal * 4.0 / 3.0;
"markdown.preview.fontSize" = sizes.terminal * 4.0 / 3.0;
"terminal.integrated.fontSize" = sizes.terminal * 4.0 / 3.0;
"chat.editor.fontSize" = sizes.terminal * 4.0 / 3.0;
# other factors (9/14, 13/14, 56/14) based on default for given value
# divided by default for `editor.fontSize` (14) from
# https://code.visualstudio.com/docs/getstarted/settings#_default-settings.
"editor.minimap.sectionHeaderFontSize" =
sizes.terminal * 4.0 / 3.0 * 9.0 / 14.0;
"scm.inputFontSize" = sizes.terminal * 4.0 / 3.0 * 13.0 / 14.0;
"screencastMode.fontSize" = sizes.terminal * 4.0 / 3.0 * 56.0 / 14.0;
};
};
}) cfg.profileNames
);
warnings =
lib.optional
(
config.programs.vscode.enable
&& config.stylix.targets.vscode.profileNames == [ ]
)
lib.optional (config.programs.vscode.enable && cfg.profileNames == [ ])
''stylix: vscode: `config.stylix.targets.vscode.profileNames` is not set. Declare profile names with 'config.stylix.targets.vscode.profileNames = [ "<PROFILE_NAME>" ];'.'';
};
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,29 @@
{ config, ... }:
with config.stylix.fonts;
{
"workbench.colorTheme" = "Stylix";
"editor.fontFamily" = monospace.name;
"editor.inlayHints.fontFamily" = monospace.name;
"editor.inlineSuggest.fontFamily" = monospace.name;
"scm.inputFontFamily" = monospace.name;
"debug.console.fontFamily" = monospace.name;
"markdown.preview.fontFamily" = sansSerif.name;
"chat.editor.fontFamily" = monospace.name;
# 4/3 factor used for pt to px;
"editor.fontSize" = sizes.terminal * 4.0 / 3.0;
"debug.console.fontSize" = sizes.terminal * 4.0 / 3.0;
"markdown.preview.fontSize" = sizes.terminal * 4.0 / 3.0;
"terminal.integrated.fontSize" = sizes.terminal * 4.0 / 3.0;
"chat.editor.fontSize" = sizes.terminal * 4.0 / 3.0;
# other factors (9/14, 13/14, 56/14) based on default for given value
# divided by default for `editor.fontSize` (14) from
# https://code.visualstudio.com/docs/getstarted/settings#_default-settings.
"editor.minimap.sectionHeaderFontSize" =
sizes.terminal * 4.0 / 3.0 * 9.0 / 14.0;
"scm.inputFontSize" = sizes.terminal * 4.0 / 3.0 * 13.0 / 14.0;
"screencastMode.fontSize" = sizes.terminal * 4.0 / 3.0 * 56.0 / 14.0;
}

File diff suppressed because it is too large Load diff

View file

@ -2,14 +2,13 @@
#! nix-shell -i python3 -p python3Packages.markdown-it-py python3Packages.requests
# This script parses the reference page and updates our template with any
# added or removed settings.
# added or removed settings, then sorts the template alphabetically.
#
# New settings are null by default. VSCode can handle this gracefully, but
# normally a value should be chosen before committing the update.
#
# This only updates 'colors' and not 'tokenColors' for now.
import json
import os
from markdown_it import MarkdownIt
import requests
@ -22,15 +21,39 @@ color_names = [
if token.type == 'inline' and token.children[0].type == 'code_inline'
]
template_path = os.path.join(os.path.dirname(__file__), 'template.mustache')
template_path = os.path.join(os.path.dirname(__file__), 'templates/theme.nix')
before_lines = []
color_lines = []
after_lines = []
with open(template_path, 'r') as template_file:
template = json.load(template_file)
while line := template_file.readline():
before_lines.append(line)
template['colors'] = {
color_name: template['colors'].get(color_name)
for color_name in color_names
}
if line == ' colors = {\n':
break
while line := template_file.readline():
if line == ' };\n':
after_lines.append(line)
break
name = line.split('"')[1]
if name in color_names:
color_lines.append(line)
color_names.remove(name)
else:
print('-', name)
for name in color_names:
print('+', name)
color_lines.append(f' "{name}" = null;\n')
color_lines.sort()
after_lines.extend(template_file.readlines())
with open(template_path, 'w') as template_file:
json.dump(template, template_file, indent=4)
template_file.writelines(before_lines + color_lines + after_lines)