modules: {
  pkgs,
  config,
  lib,
  helpers,
  ...
}: let
  inherit (lib) types;
  fileModuleType = types.submoduleWith {
    shorthandOnlyDefinesConfig = true;
    specialArgs.helpers = helpers;
    modules = [
      ({
        name,
        config,
        ...
      }: {
        imports = modules;
        options.plugin = lib.mkOption {
          type = types.package;
          description = "A derivation with the content of the file in it";
          readOnly = true;
          internal = true;
        };
        config = {
          path = name;
          type = lib.mkDefault (
            if lib.hasSuffix ".vim" name
            then "vim"
            else "lua"
          );
          plugin = pkgs.writeTextDir config.path config.content;
        };
      })
    ];
  };
in {
  options = {
    files = lib.mkOption {
      type = types.attrsOf fileModuleType;
      description = "Files to include in the Vim config.";
      default = {};
    };

    filesPlugin = lib.mkOption {
      type = types.package;
      description = "A derivation with all the files inside.";
      internal = true;
      readOnly = true;
    };
  };

  config = let
    inherit (config) files;
    concatFilesOption = attr:
      lib.flatten (lib.mapAttrsToList (_: builtins.getAttr attr) files);
  in {
    # Each file can declare plugins/packages/warnings/assertions
    extraPlugins = concatFilesOption "extraPlugins";
    extraPackages = concatFilesOption "extraPackages";
    warnings = concatFilesOption "warnings";
    assertions = concatFilesOption "assertions";

    # A directory with all the files in it
    filesPlugin = pkgs.buildEnv {
      name = "nixvim-config";
      paths =
        (lib.mapAttrsToList (_: file: file.plugin) files)
        ++ (lib.mapAttrsToList pkgs.writeTextDir config.extraFiles);
    };
  };
}