Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib/options: introduce "prime" fn variants (alt API) #1603

Merged
merged 12 commits into from
Jun 1, 2024
227 changes: 148 additions & 79 deletions lib/options.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,75 +7,116 @@ with lib;
with nixvimUtils;
rec {
# Creates an option with a nullable type that defaults to null.
mkNullOrOption =
type: desc:
lib.mkOption {
type = lib.types.nullOr type;
default = null;
description = desc;
};
mkNullOrOption' =
{
type,
default ? null,
...
}@args:
lib.mkOption (
args
// {
type = lib.types.nullOr type;
inherit default;
}
);
mkNullOrOption = type: description: mkNullOrOption' { inherit type description; };

mkCompositeOption = desc: options: mkNullOrOption (types.submodule { inherit options; }) desc;
mkCompositeOption' =
{ options, ... }@args:
mkNullOrOption' (
(filterAttrs (n: _: n != "options") args) // { type = types.submodule { inherit options; }; }
);
mkCompositeOption = description: options: mkCompositeOption' { inherit description options; };

mkNullOrStr = mkNullOrOption (with nixvimTypes; maybeRaw str);
mkNullOrStr' = args: mkNullOrOption' (args // { type = with nixvimTypes; maybeRaw str; });
mkNullOrStr = description: mkNullOrStr' { inherit description; };

mkNullOrLua =
desc:
lib.mkOption {
type = lib.types.nullOr nixvimTypes.strLua;
default = null;
description = desc;
apply = mkRaw;
};
mkNullOrLua' =
args:
mkNullOrOption' (
args
// {
type = nixvimTypes.strLua;
apply = mkRaw;
}
);
mkNullOrLua = description: mkNullOrLua' { inherit description; };

mkNullOrLuaFn =
desc:
lib.mkOption {
type = lib.types.nullOr nixvimTypes.strLuaFn;
default = null;
description = desc;
apply = mkRaw;
};
mkNullOrLuaFn' =
args:
mkNullOrOption' (
args
// {
type = nixvimTypes.strLuaFn;
apply = mkRaw;
}
);
mkNullOrLuaFn = description: mkNullOrLua' { inherit description; };

mkNullOrStrLuaOr =
ty: desc:
lib.mkOption {
type = lib.types.nullOr (types.either nixvimTypes.strLua ty);
default = null;
description = desc;
apply = v: if builtins.isString v then mkRaw v else v;
};
mkNullOrStrLuaOr' =
{ type, ... }@args:
mkNullOrOption' (
args
// {
type = with nixvimTypes; either strLua type;
apply = v: if isString v then mkRaw v else v;
}
);
mkNullOrStrLuaOr = type: description: mkNullOrStrLuaOr' { inherit type description; };

mkNullOrStrLuaFnOr =
ty: desc:
lib.mkOption {
type = lib.types.nullOr (types.either nixvimTypes.strLuaFn ty);
default = null;
description = desc;
apply = v: if builtins.isString v then mkRaw v else v;
};
mkNullOrStrLuaFnOr' =
{ type, ... }@args:
mkNullOrOption' (
args
// {
type = with nixvimTypes; either strLuaFn type;
apply = v: if isString v then mkRaw v else v;
}
);
mkNullOrStrLuaFnOr = type: description: mkNullOrStrLuaFnOr' { inherit type description; };

defaultNullOpts = rec {
# Description helpers
mkDefaultDesc =
defaultValue:
let
default =
# Assume a string default is already formatted as intended,
# historically strings were the only type accepted here.
# TODO consider deprecating this behavior so we can properly quote strings
if isString defaultValue then defaultValue else generators.toPretty { } defaultValue;
in
"Plugin default:"
+ (
# Detect whether `default` is multiline or inline:
if hasInfix "\n" default then "\n\n```nix\n${default}\n```" else " `${default}`"
);
/**
Build a description with a plugin default.

The [default] can be any value, and it will be formatted using `lib.generators.toPretty`.

If [default] is a String, it will not be formatted.
This behavior will likely change in the future.

# Example
```nix
mkDesc 1 "foo"
=> ''
foo

Plugin default: `1`
''
```

# Type
```
mkDesc :: Any -> String -> String
```

# Arguments
- [default] The plugin's default
- [desc] The option's description
*/
mkDesc =
default: desc:
let
defaultDesc = mkDefaultDesc default;
# Assume a string default is already formatted as intended,
# historically strings were the only type accepted here.
# TODO deprecate this behavior so we can properly quote strings
defaultString = if isString default then default else generators.toPretty { } default;
defaultDesc =
"Plugin default:"
+ (
# Detect whether `default` is multiline or inline:
if hasInfix "\n" defaultString then "\n\n```nix\n${defaultString}\n```" else " `${defaultString}`"
);
in
if desc == "" then
defaultDesc
Expand All @@ -86,11 +127,24 @@ rec {
${defaultDesc}
'';

mkNullable' =
{ default, description, ... }@args:
mkNullOrOption' (
args
// {
default = null;
description = mkDesc default description;
}
);
mkNullable =
type: default: desc:
mkNullOrOption type (mkDesc default desc);
type: default: description:
mkNullable' { inherit type default description; };

mkNullableWithRaw = type: mkNullable (nixvimTypes.maybeRaw type);
mkNullableWithRaw' =
{ type, ... }@args: mkNullable' (args // { type = nixvimTypes.maybeRaw type; });
mkNullableWithRaw =
type: default: description:
mkNullableWithRaw' { inherit type default description; };

mkStrLuaOr =
type: default: desc:
Expand All @@ -117,9 +171,22 @@ rec {
default:
assert default == null || isString default;
mkNullableWithRaw types.str (generators.toPretty { } default);
mkAttributeSet = mkNullable nixvimTypes.attrs;
mkListOf = ty: default: mkNullable (with nixvimTypes; listOf (maybeRaw ty)) default;
mkAttrsOf = ty: default: mkNullable (with nixvimTypes; attrsOf (maybeRaw ty)) default;

mkAttributeSet' = args: mkNullable' (args // { type = nixvimTypes.attrs; });
mkAttributeSet = default: description: mkAttributeSet' { inherit default description; };

mkListOf' =
{ type, ... }@args: mkNullable' (args // { type = with nixvimTypes; listOf (maybeRaw type); });
mkListOf =
type: default: description:
mkListOf' { inherit type default description; };

mkAttrsOf' =
{ type, ... }@args: mkNullable' (args // { type = with nixvimTypes; attrsOf (maybeRaw type); });
mkAttrsOf =
type: default: description:
mkAttrsOf' { inherit type default description; };

mkEnum =
enumValues: default:
mkNullableWithRaw (types.enum enumValues) (
Expand Down Expand Up @@ -181,23 +248,25 @@ rec {

mkPackageOption =
{
name ? null, # Can be null if a custom description is given.
default,
name ? null, # Can be omitted if a custom description is given.
description ? null,
example ? null,
}:
mkOption {
type = with types; nullOr package;
inherit default example;
description =
if description == null then
''
Which package to use for `${name}`.
Set to `null` to disable its automatic installation.
''
else
description;
};
default, # `default` is not optional
...
}@args:
mkNullOrOption' (
(filterAttrs (n: _: n != "name") args)
// {
type = types.package;
description =
if description == null then
''
Which package to use for `${name}`.
Set to `null` to disable its automatic installation.
''
else
description;
}
);

mkPluginPackageOption =
name: default:
Expand Down