mirror of
https://github.com/nix-community/nixvim.git
synced 2025-12-13 12:31:08 +01:00
Instead of copying source files to the target, use a symlink. This reduces nix store redundancy and enables using entire directories as sources. To support this, additional validation is done on file targets to prevent unexpected conflicts.
151 lines
4.7 KiB
Nix
151 lines
4.7 KiB
Nix
{
|
|
pkgs,
|
|
config,
|
|
options,
|
|
lib,
|
|
specialArgs,
|
|
...
|
|
}:
|
|
let
|
|
inherit (lib) types;
|
|
|
|
fileModuleType = types.submoduleWith {
|
|
inherit specialArgs;
|
|
# Don't include the modules in the docs, as that'd be redundant
|
|
modules = lib.optionals (!config.isDocs) [
|
|
../../.
|
|
./submodule.nix
|
|
# Pass module args through to the submodule (except `name`)
|
|
# Wrap each arg with the correct priority
|
|
{
|
|
_module.args = lib.pipe options._module.args [
|
|
lib.modules.mergeAttrDefinitionsWithPrio
|
|
(lib.flip builtins.removeAttrs [ "name" ])
|
|
(lib.mapAttrs (_: { highestPrio, value }: lib.mkOverride highestPrio value))
|
|
];
|
|
}
|
|
];
|
|
description = "Nixvim configuration";
|
|
};
|
|
in
|
|
{
|
|
options = {
|
|
files = lib.mkOption {
|
|
type = types.attrsOf fileModuleType;
|
|
description = "Extra files to add to the runtimepath";
|
|
default = { };
|
|
example = {
|
|
"ftplugin/nix.lua" = {
|
|
opts = {
|
|
tabstop = 2;
|
|
shiftwidth = 2;
|
|
expandtab = true;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
build.extraFiles = lib.mkOption {
|
|
type = types.package;
|
|
description = "A derivation with all the files inside.";
|
|
internal = true;
|
|
readOnly = true;
|
|
};
|
|
};
|
|
|
|
config =
|
|
let
|
|
extraFiles = lib.filter (file: file.enable) (lib.attrValues config.extraFiles);
|
|
targets = lib.pipe extraFiles [
|
|
(builtins.groupBy (entry: entry.target))
|
|
# Explicitly copy to store using "${}"
|
|
(lib.mapAttrs (_: map (entry: "${entry.finalSource}")))
|
|
];
|
|
prefixConflicts = lib.optionals (targets != { }) (
|
|
let
|
|
names = lib.attrNames targets;
|
|
pairs = lib.zipLists names (lib.tail names);
|
|
in
|
|
lib.filter ({ fst, snd }: lib.hasPrefix "${fst}/" snd) pairs
|
|
);
|
|
|
|
concatFilesOption = attr: lib.flatten (lib.mapAttrsToList (_: builtins.getAttr attr) config.files);
|
|
in
|
|
{
|
|
# Each file can declare plugins/packages/warnings/assertions
|
|
extraPlugins = concatFilesOption "extraPlugins";
|
|
extraPackages = concatFilesOption "extraPackages";
|
|
warnings = concatFilesOption "warnings";
|
|
assertions =
|
|
concatFilesOption "assertions"
|
|
++ lib.nixvim.mkAssertions "extraFiles" {
|
|
assertion = prefixConflicts == [ ];
|
|
message = ''
|
|
Conflicting target prefixes:
|
|
${lib.concatMapStringsSep "\n" ({ fst, snd }: " - ${fst} ↔ ${snd}") prefixConflicts}
|
|
'';
|
|
};
|
|
|
|
# Add files to extraFiles
|
|
extraFiles = lib.mkDerivedConfig options.files (
|
|
lib.mapAttrs' (
|
|
_: file: {
|
|
name = file.path;
|
|
value.source = file.plugin;
|
|
}
|
|
)
|
|
);
|
|
|
|
# A directory with all the files in it
|
|
# Implementation inspired by NixOS's /etc module
|
|
build.extraFiles =
|
|
pkgs.runCommandLocal "nvim-config"
|
|
{
|
|
__structuredAttrs = true;
|
|
nativeBuildInputs = [ pkgs.jq ];
|
|
inherit targets;
|
|
passthru.vimPlugin = true;
|
|
}
|
|
''
|
|
set -euo pipefail
|
|
|
|
# Ensure $out is created, in case there are no targets defined
|
|
mkdir -p "$out"
|
|
|
|
# Extract targets into a dedicated file,
|
|
# to avoid reading all of attrs.json multiple times
|
|
jq .targets "$NIX_ATTRS_JSON_FILE" > targets.json
|
|
|
|
# Iterate target keys and read sources into a bash array
|
|
jq --raw-output 'keys[]' targets.json |
|
|
while IFS= read -r target; do
|
|
# read the list of source strings for this target into a Bash array
|
|
mapfile -t sources < <(
|
|
jq --raw-output --arg target "$target" '.[$target][]' targets.json
|
|
)
|
|
|
|
# If there are multiple sources, ensure all are identical
|
|
if (( ''${#sources[@]} > 1 )); then
|
|
base="''${sources[0]}"
|
|
for src in "''${sources[@]:1}"; do
|
|
# Optimistically check store-path equality, then fallback to diff
|
|
if [ "$src" != "$base" ] && ! diff -q "$base" "$src" >/dev/null
|
|
then
|
|
echo "error: target '$target' defined multiple times with different sources:" >&2
|
|
printf ' %s\n' "''${sources[@]}" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Install target symlink to the canonical source
|
|
dest="$out/$target"
|
|
mkdir -p "$(dirname "$dest")"
|
|
ln -s "''${sources[0]}" "$dest"
|
|
done
|
|
'';
|
|
|
|
# Never combine user files with the rest of the plugins
|
|
performance.combinePlugins.standalonePlugins = [ config.build.extraFiles ];
|
|
};
|
|
}
|