vscode: support path literals in userSettings

programs.vscode.profiles.<name>.userSettings accepts either JSON settings or a path to a settings.json file. The update-check defaults were merged into userSettings before deciding whether to generate JSON or link a source file, so path values failed when Nix tried to apply // to them.

Skip those merges for path-like values and use the shared isPathLike helper for VS Code's source-or-generated JSON options so Nix paths, store path strings, and derivation outputs are handled consistently.

Fixes #7726
This commit is contained in:
Austin Horstman
2026-06-10 13:10:31 -05:00
parent 2b394beca7
commit f96f717a47
4 changed files with 58 additions and 21 deletions
+21 -21
View File
@@ -22,6 +22,7 @@ let
optionalString
types
;
inherit (lib.hm.strings) isPathLike;
moduleName = lib.concatStringsSep "." modulePath;
@@ -60,15 +61,16 @@ let
mergedUserSettings =
userSettings: enableUpdateCheck: enableExtensionUpdateCheck:
userSettings
// lib.optionalAttrs (enableUpdateCheck == false) {
"update.mode" = "none";
}
// lib.optionalAttrs (enableExtensionUpdateCheck == false) {
"extensions.autoCheckUpdates" = false;
};
isPath = p: builtins.isPath p || lib.isStorePath p;
if isPathLike userSettings then
userSettings
else
userSettings
// lib.optionalAttrs (enableUpdateCheck == false) {
"update.mode" = "none";
}
// lib.optionalAttrs (enableExtensionUpdateCheck == false) {
"extensions.autoCheckUpdates" = false;
};
transformMcpServerForVscode = name: server: {
inherit name;
@@ -372,28 +374,26 @@ in
home.file = lib.mkMerge (flatten [
(mkIf (cfg.argvSettings != { }) {
"${argvPath}".source =
if isPath cfg.argvSettings then
if isPathLike cfg.argvSettings then
cfg.argvSettings
else
jsonFormat.generate "vscode-argv" cfg.argvSettings;
})
(mapAttrsToList (n: v: [
(mkIf ((mergedUserSettings v.userSettings v.enableUpdateCheck v.enableExtensionUpdateCheck) != { })
{
(
let
merged = mergedUserSettings v.userSettings v.enableUpdateCheck v.enableExtensionUpdateCheck;
in
mkIf (merged != { }) {
"${configFilePath n}".source =
if isPath v.userSettings then
v.userSettings
else
jsonFormat.generate "vscode-user-settings" (
mergedUserSettings v.userSettings v.enableUpdateCheck v.enableExtensionUpdateCheck
);
if isPathLike merged then merged else jsonFormat.generate "vscode-user-settings" merged;
}
)
(mkIf (v.userTasks != { }) {
"${tasksFilePath n}".source =
if isPath v.userTasks then v.userTasks else jsonFormat.generate "vscode-user-tasks" v.userTasks;
if isPathLike v.userTasks then v.userTasks else jsonFormat.generate "vscode-user-tasks" v.userTasks;
})
(mkIf
@@ -403,7 +403,7 @@ in
)
{
"${mcpFilePath n}".source =
if isPath v.userMcp then
if isPathLike v.userMcp then
v.userMcp
else
let
@@ -424,7 +424,7 @@ in
(mkIf (v.keybindings != [ ]) {
"${keybindingsFilePath n}".source =
if isPath v.keybindings then
if isPathLike v.keybindings then
v.keybindings
else
jsonFormat.generate "vscode-keybindings" (map (lib.filterAttrs (_: v: v != null)) v.keybindings);
@@ -14,6 +14,7 @@ let
mcp-integration = import ./mcp-integration.nix;
mcp-integration-with-override = import ./mcp-integration-with-override.nix;
update-checks = import ./update-checks.nix;
path-literal = import ./path-literal.nix;
snippets = import ./snippets.nix;
null-package = import ./null-package.nix;
fork-package-warning = import ./fork-package-warning.nix;
@@ -0,0 +1,3 @@
{
"editor.fontSize": 18
}
@@ -0,0 +1,33 @@
package:
{
pkgs,
...
}:
let
settingsPath =
if pkgs.stdenv.hostPlatform.isDarwin then
"Library/Application Support/Code/User/settings.json"
else
".config/Code/User/settings.json";
in
{
programs.vscode = {
enable = true;
inherit package;
profiles = {
default = {
userSettings = ./path-literal-settings.json;
enableUpdateCheck = false;
enableExtensionUpdateCheck = false;
};
};
};
nmt.script = ''
assertFileExists "home-files/${settingsPath}"
assertFileContent "home-files/${settingsPath}" "${./path-literal-settings.json}"
'';
}