2024-07-28 22:51:18 +01:00
|
|
|
|
{ lib }:
|
2024-06-24 12:16:54 +01:00
|
|
|
|
rec {
|
|
|
|
|
# Get a (sub)option by walking the path,
|
|
|
|
|
# checking for submodules along the way
|
|
|
|
|
getOptionRecursive =
|
|
|
|
|
opt: prefix: optionPath:
|
|
|
|
|
if optionPath == [ ] then
|
|
|
|
|
opt
|
2024-08-30 14:49:20 -05:00
|
|
|
|
else if lib.isOption opt then
|
2024-06-24 12:16:54 +01:00
|
|
|
|
getOptionRecursive (opt.type.getSubOptions prefix) prefix optionPath
|
|
|
|
|
else
|
|
|
|
|
let
|
2024-08-30 14:49:20 -05:00
|
|
|
|
name = lib.head optionPath;
|
|
|
|
|
opt' = lib.getAttr name opt;
|
2024-06-24 12:16:54 +01:00
|
|
|
|
prefix' = prefix ++ [ name ];
|
2024-08-30 14:49:20 -05:00
|
|
|
|
optionPath' = lib.drop 1 optionPath;
|
2024-06-24 12:16:54 +01:00
|
|
|
|
in
|
|
|
|
|
getOptionRecursive opt' prefix' optionPath';
|
|
|
|
|
|
|
|
|
|
# Like mkRemovedOptionModule, but has support for nested sub-options
|
|
|
|
|
# and uses warnings instead of assertions.
|
|
|
|
|
mkDeprecatedSubOptionModule =
|
|
|
|
|
optionPath: replacementInstructions:
|
|
|
|
|
{ options, ... }:
|
|
|
|
|
{
|
2024-08-30 14:49:20 -05:00
|
|
|
|
options = lib.setAttrByPath optionPath (
|
|
|
|
|
lib.mkOption {
|
|
|
|
|
# When (e.g.) `mkAttrs` is used on a submodule, this option will be evaluated.
|
|
|
|
|
# Therefore we have to apply _something_ (null) when there's no definition.
|
|
|
|
|
apply =
|
|
|
|
|
v:
|
|
|
|
|
let
|
|
|
|
|
# Avoid "option used but not defined" errors
|
|
|
|
|
res = builtins.tryEval v;
|
|
|
|
|
in
|
|
|
|
|
if res.success then res.value else null;
|
|
|
|
|
visible = false;
|
|
|
|
|
}
|
|
|
|
|
);
|
2024-06-24 12:16:54 +01:00
|
|
|
|
config.warnings =
|
|
|
|
|
let
|
|
|
|
|
opt = getOptionRecursive options [ ] optionPath;
|
|
|
|
|
in
|
2024-08-30 14:49:20 -05:00
|
|
|
|
lib.optional opt.isDefined ''
|
|
|
|
|
The option definition `${lib.showOption optionPath}' in ${lib.showFiles opt.files} is deprecated.
|
2024-06-24 12:16:54 +01:00
|
|
|
|
${replacementInstructions}
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-16 09:01:16 +01:00
|
|
|
|
/*
|
|
|
|
|
Returns a function that maps
|
|
|
|
|
[
|
|
|
|
|
"someOption"
|
|
|
|
|
["fooBar" "someSubOption"]
|
|
|
|
|
{ old = "someOtherOption"; new = ["foo_bar" "some_other_option"]}
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
to
|
|
|
|
|
[
|
|
|
|
|
(lib.mkRenamedOptionModule
|
|
|
|
|
(oldPath ++ ["someOption"])
|
|
|
|
|
(newPath ++ ["some_option"])
|
|
|
|
|
)
|
|
|
|
|
(lib.mkRenamedOptionModule
|
|
|
|
|
(oldPath ++ ["fooBar" "someSubOption"])
|
|
|
|
|
(newPath ++ ["foo_bar" "some_sub_option"])
|
|
|
|
|
)
|
|
|
|
|
(lib.mkRenamedOptionModule
|
|
|
|
|
(oldPath ++ ["someOtherOption"])
|
|
|
|
|
(newPath ++ ["foo_bar" "some_other_option"])
|
|
|
|
|
)
|
|
|
|
|
]
|
|
|
|
|
*/
|
2024-08-13 09:23:17 -05:00
|
|
|
|
mkSettingsRenamedOptionModules =
|
|
|
|
|
oldPrefix: newPrefix:
|
|
|
|
|
map (
|
2024-12-16 09:01:16 +01:00
|
|
|
|
spec:
|
2024-08-13 09:23:17 -05:00
|
|
|
|
let
|
2024-12-16 09:01:16 +01:00
|
|
|
|
finalSpec =
|
|
|
|
|
if lib.isAttrs spec then
|
|
|
|
|
lib.mapAttrs (_: lib.toList) spec
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
old = lib.toList spec;
|
|
|
|
|
new = map lib.nixvim.toSnakeCase finalSpec.old;
|
|
|
|
|
};
|
2024-08-13 09:23:17 -05:00
|
|
|
|
in
|
2024-12-16 09:01:16 +01:00
|
|
|
|
lib.mkRenamedOptionModule (oldPrefix ++ finalSpec.old) (newPrefix ++ finalSpec.new)
|
2024-08-13 09:23:17 -05:00
|
|
|
|
);
|
|
|
|
|
|
2024-07-07 16:01:10 +01:00
|
|
|
|
# A clone of types.coercedTo, but it prints a warning when oldType is used.
|
|
|
|
|
transitionType =
|
|
|
|
|
oldType: coerceFn: newType:
|
|
|
|
|
assert lib.assertMsg (
|
|
|
|
|
oldType.getSubModules == null
|
|
|
|
|
) "transitionType: oldType must not have submodules (it’s a ${oldType.description})";
|
|
|
|
|
lib.mkOptionType rec {
|
|
|
|
|
name = "transitionType";
|
|
|
|
|
inherit (newType) description;
|
|
|
|
|
check = x: (oldType.check x && newType.check (coerceFn x)) || newType.check x;
|
|
|
|
|
merge =
|
|
|
|
|
opt: defs:
|
|
|
|
|
let
|
|
|
|
|
coerceVal =
|
|
|
|
|
val:
|
|
|
|
|
if oldType.check val then
|
|
|
|
|
lib.warn ''
|
|
|
|
|
Passing a ${oldType.description} for `${lib.showOption opt}' is deprecated, use ${newType.description} instead. Definitions: ${lib.options.showDefs defs}
|
|
|
|
|
'' (coerceFn val)
|
|
|
|
|
else
|
|
|
|
|
val;
|
|
|
|
|
in
|
|
|
|
|
newType.merge opt (map (def: def // { value = coerceVal def.value; }) defs);
|
|
|
|
|
inherit (newType) emptyValue;
|
|
|
|
|
inherit (newType) getSubOptions;
|
|
|
|
|
inherit (newType) getSubModules;
|
|
|
|
|
substSubModules = m: transitionType oldType coerceFn (newType.substSubModules m);
|
|
|
|
|
typeMerge = t1: t2: null;
|
|
|
|
|
functor = (lib.types.defaultFunctor name) // {
|
|
|
|
|
wrapped = newType;
|
|
|
|
|
};
|
|
|
|
|
nestedTypes.coercedType = oldType;
|
|
|
|
|
nestedTypes.finalType = newType;
|
|
|
|
|
};
|
2025-04-06 17:17:51 +02:00
|
|
|
|
|
|
|
|
|
mkRemovedPackageOptionModule =
|
|
|
|
|
{
|
|
|
|
|
plugin,
|
|
|
|
|
packageName,
|
|
|
|
|
oldPackageName ? packageName,
|
|
|
|
|
}:
|
2025-04-14 16:59:35 +01:00
|
|
|
|
{ config, options, ... }:
|
2025-04-07 17:22:34 +02:00
|
|
|
|
let
|
2025-04-14 16:59:35 +01:00
|
|
|
|
cfg = config.dependencies.${packageName};
|
|
|
|
|
opt = options.dependencies.${packageName};
|
|
|
|
|
oldOptPath = builtins.concatMap lib.toList [
|
2025-04-12 04:36:02 +01:00
|
|
|
|
"plugins"
|
|
|
|
|
plugin
|
|
|
|
|
"${oldPackageName}Package"
|
|
|
|
|
];
|
2025-04-14 16:59:35 +01:00
|
|
|
|
oldOpt = lib.getAttrFromPath oldOptPath options;
|
|
|
|
|
|
|
|
|
|
# We can't use `oldOpt.value` because that will use our `apply`, so we merge the definitions ourselves:
|
|
|
|
|
oldDef = lib.modules.mergeDefinitions oldOpt.loc oldOpt.type oldOpt.definitionsWithLocations;
|
2025-04-12 04:36:02 +01:00
|
|
|
|
|
2025-04-14 16:59:35 +01:00
|
|
|
|
# Conceptually similar to `mkDerivedConfig`, but uses our manually merged definition
|
|
|
|
|
configFromOldDef =
|
|
|
|
|
{
|
|
|
|
|
predicate ? _: true,
|
|
|
|
|
apply ? lib.id,
|
|
|
|
|
}:
|
|
|
|
|
let
|
|
|
|
|
inherit (oldDef) mergedValue isDefined;
|
|
|
|
|
inherit (oldDef.defsFinal') highestPrio;
|
|
|
|
|
condition = isDefined && predicate mergedValue;
|
|
|
|
|
value = apply mergedValue;
|
|
|
|
|
in
|
|
|
|
|
lib.mkIf condition (lib.mkOverride highestPrio value);
|
2025-04-07 17:22:34 +02:00
|
|
|
|
in
|
2025-04-12 04:36:02 +01:00
|
|
|
|
{
|
2025-04-14 16:59:35 +01:00
|
|
|
|
options = lib.setAttrByPath oldOptPath (
|
|
|
|
|
lib.mkOption {
|
|
|
|
|
type = with lib.types; nullOr package;
|
|
|
|
|
description = "Alias of `${opt.enable}` and `${opt.package}`.";
|
|
|
|
|
visible = false;
|
|
|
|
|
apply =
|
|
|
|
|
let
|
|
|
|
|
value = if cfg.enable then cfg.package else null;
|
|
|
|
|
use = builtins.trace "Obsolete option `${oldOpt}' is used. It was replaced by `${opt.enable}' and `${opt.package}'.";
|
|
|
|
|
in
|
|
|
|
|
_: use value;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
config = lib.mkIf oldOpt.isDefined {
|
|
|
|
|
warnings = [
|
|
|
|
|
"The option `${oldOpt}' defined in ${lib.showFiles oldOpt.files} has been replaced by `${opt.enable}' and `${opt.package}'."
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
dependencies.${packageName} = {
|
|
|
|
|
enable = configFromOldDef {
|
|
|
|
|
apply = pkg: pkg != null;
|
|
|
|
|
};
|
|
|
|
|
package = configFromOldDef {
|
|
|
|
|
predicate = pkg: pkg != null;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
2025-04-12 04:36:02 +01:00
|
|
|
|
};
|
2024-06-24 12:16:54 +01:00
|
|
|
|
}
|