mirror of
https://github.com/nix-community/home-manager.git
synced 2025-11-08 19:46:05 +01:00
Merge branch 'nix-community:master' into ssh-kex-algo
This commit is contained in:
commit
a73706f970
42 changed files with 599 additions and 590 deletions
16
Justfile
Normal file
16
Justfile
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Common commands
|
||||
#
|
||||
# Contributing manual:
|
||||
# - https://nix-community.github.io/home-manager/#ch-contributing
|
||||
|
||||
# List tests matching a pattern `pattern`
|
||||
list *pattern:
|
||||
nix run .#tests -- -l {{pattern}}
|
||||
|
||||
# Run all tests matching a pattern `pattern`
|
||||
test *pattern:
|
||||
nix run .#tests -- {{pattern}}
|
||||
|
||||
# Run integration tests
|
||||
integration_tests:
|
||||
nix run .#tests -- -t -l
|
||||
6
flake.lock
generated
6
flake.lock
generated
|
|
@ -2,11 +2,11 @@
|
|||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1761907660,
|
||||
"narHash": "sha256-kJ8lIZsiPOmbkJypG+B5sReDXSD1KGu2VEPNqhRa/ew=",
|
||||
"lastModified": 1762111121,
|
||||
"narHash": "sha256-4vhDuZ7OZaZmKKrnDpxLZZpGIJvAeMtK6FKLJYUtAdw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "2fb006b87f04c4d3bdf08cfdbc7fab9c13d94a15",
|
||||
"rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
|||
14
modules/misc/news/2025/11/2025-11-03_22-56-50.nix
Normal file
14
modules/misc/news/2025/11/2025-11-03_22-56-50.nix
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{ config, pkgs, ... }:
|
||||
{
|
||||
time = "2025-11-03T21:56:50+00:00";
|
||||
condition = config.programs.ghostty.enable && pkgs.stdenv.hostPlatform.isLinux;
|
||||
message = ''
|
||||
Ghostty: now enables the user systemd service by default.
|
||||
|
||||
Running Ghostty via these systemd units is the recommended way to run
|
||||
Ghostty. The two most important benefits provided by Ghostty's systemd
|
||||
integrations are: instantaneous launching and centralized logging.
|
||||
|
||||
See https://ghostty.org/docs/linux/systemd for all details
|
||||
'';
|
||||
}
|
||||
11
modules/misc/news/2025/11/2025-11-04_13-00-00.nix
Normal file
11
modules/misc/news/2025/11/2025-11-04_13-00-00.nix
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
time = "2025-11-04T13:00:00+00:00";
|
||||
condition = true;
|
||||
message = ''
|
||||
A new module is available: 'programs.opkssh'.
|
||||
|
||||
opkssh is a tool which enables ssh to be used with OpenID Connect allowing SSH access to be managed via identities instead of long-lived SSH keys. It does not replace SSH, but instead generates SSH public keys containing PK Tokens and configures sshd to verify them. These PK Tokens contain standard OpenID Connect ID Tokens.
|
||||
|
||||
This protocol builds on the OpenPubkey which adds user public keys to OpenID Connect without breaking compatibility with existing OpenID Provider.
|
||||
'';
|
||||
}
|
||||
9
modules/misc/news/2025/11/2025-11-06_12-50-53.nix
Normal file
9
modules/misc/news/2025/11/2025-11-06_12-50-53.nix
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
time = "2025-11-06T11:50:53+00:00";
|
||||
condition = true;
|
||||
message = ''
|
||||
A new module is available: 'services.tomat'.
|
||||
|
||||
tomat is a Pomodoro timer for status bars and the command line. It is easily configurable and support both desktop and sound notifications.
|
||||
'';
|
||||
}
|
||||
|
|
@ -9,175 +9,6 @@ let
|
|||
|
||||
cfg = config.systemd.user.tmpfiles;
|
||||
|
||||
ruleSubmodule = lib.types.submodule (
|
||||
{ name, ... }:
|
||||
{
|
||||
options.type = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
readOnly = true;
|
||||
default = name;
|
||||
defaultText = "‹tmpfiles-type›";
|
||||
example = "d";
|
||||
description = ''
|
||||
The type of operation to perform on the file.
|
||||
|
||||
The type consists of a single letter and optionally one or more
|
||||
modifier characters.
|
||||
|
||||
Please see the upstream documentation for the available types and
|
||||
more details: {manpage}`tmpfiles.d(5)`
|
||||
'';
|
||||
};
|
||||
options.mode = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "-";
|
||||
example = "0755";
|
||||
description = ''
|
||||
The file access mode to use when creating this file or directory.
|
||||
'';
|
||||
};
|
||||
options.user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "-";
|
||||
example = "root";
|
||||
description = ''
|
||||
The user of the file.
|
||||
|
||||
This may either be a numeric ID or a user/group name.
|
||||
|
||||
If omitted or when set to `"-"`, the user and group of the user who
|
||||
invokes systemd-tmpfiles is used.
|
||||
'';
|
||||
};
|
||||
options.group = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "-";
|
||||
example = "root";
|
||||
description = ''
|
||||
The group of the file.
|
||||
|
||||
This may either be a numeric ID or a user/group name.
|
||||
|
||||
If omitted or when set to `"-"`, the user and group of the user who
|
||||
invokes systemd-tmpfiles is used.
|
||||
'';
|
||||
};
|
||||
options.age = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "-";
|
||||
example = "10d";
|
||||
description = ''
|
||||
Delete a file when it reaches a certain age.
|
||||
|
||||
If a file or directory is older than the current time minus the age
|
||||
field, it is deleted.
|
||||
|
||||
If set to `"-"`, no automatic clean-up is done.
|
||||
'';
|
||||
};
|
||||
options.argument = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
example = "";
|
||||
description = ''
|
||||
An argument whose meaning depends on the type of operation.
|
||||
|
||||
Please see the upstream documentation for the meaning of this
|
||||
parameter in different situations: {manpage}`tmpfiles.d(5)`
|
||||
'';
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
attrsWith' = placeholder: elemType: lib.types.attrsWith { inherit elemType placeholder; };
|
||||
|
||||
nonEmptyAttrsWith' =
|
||||
placeholder: elemType:
|
||||
let
|
||||
attrs = lib.types.addCheck (attrsWith' placeholder elemType) (s: s != { });
|
||||
in
|
||||
attrs
|
||||
// {
|
||||
name = "nonEmptyAttrsOf";
|
||||
description = "non-empty ${attrs.description}";
|
||||
emptyValue = { }; # no .value attribute, meaning there is not empty value
|
||||
substSubModules = m: nonEmptyAttrsWith' placeholder (elemType.substSubModules m);
|
||||
};
|
||||
|
||||
configSubmodule = lib.types.submodule {
|
||||
options.rules = lib.mkOption {
|
||||
description = "The rules contained in this configuration.";
|
||||
example = {
|
||||
"%C".d = {
|
||||
mode = "0755";
|
||||
user = "alice";
|
||||
group = "alice";
|
||||
age = "4 weeks";
|
||||
};
|
||||
};
|
||||
type = nonEmptyAttrsWith' "path" (nonEmptyAttrsWith' "tmpfiles-type" ruleSubmodule);
|
||||
};
|
||||
options.purgeOnChange = lib.mkOption {
|
||||
description = ''
|
||||
Whether the rules that are marked for purging, will automatically
|
||||
be purged when the set of rules changes.
|
||||
|
||||
See {manpage}`systemd-tmpfiles(8)` for details about purging.
|
||||
'';
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
};
|
||||
};
|
||||
|
||||
modulePrefix = [
|
||||
"systemd"
|
||||
"user"
|
||||
"tmpfiles"
|
||||
"settings"
|
||||
];
|
||||
|
||||
mkFileName = configName: "user-tmpfiles.d/home-manager-${configName}.conf";
|
||||
|
||||
mkConfigFile =
|
||||
name: rules:
|
||||
{
|
||||
suffix ? [ name ],
|
||||
}:
|
||||
let
|
||||
escapeArgument = lib.strings.escapeC [
|
||||
"\t"
|
||||
"\n"
|
||||
"\r"
|
||||
" "
|
||||
"\\"
|
||||
];
|
||||
mkRule = path: rule: ''
|
||||
'${rule.type}' '${path}' '${rule.mode}' '${rule.user}' '${rule.group}' '${rule.age}' ${escapeArgument rule.argument}
|
||||
'';
|
||||
in
|
||||
{
|
||||
text = ''
|
||||
# This file was generated by Home Manager and should not be modified.
|
||||
# Please change the option '${lib.showAttrPath (modulePrefix ++ suffix)}' instead.
|
||||
${lib.pipe rules [
|
||||
(lib.mapAttrs (_path: lib.attrValues))
|
||||
(lib.mapAttrsToList (path: map (mkRule path)))
|
||||
lib.flatten
|
||||
lib.concatStrings
|
||||
]}
|
||||
'';
|
||||
onChange = ''
|
||||
run ${pkgs.systemd}/bin/systemd-tmpfiles --user --remove --create ''${DRY_RUN:+--dry-run} '${config.xdg.configHome}/${mkFileName name}'
|
||||
'';
|
||||
};
|
||||
|
||||
nonPurgedConfigs = lib.filterAttrs (_name: config: !config.purgeOnChange) cfg.settings;
|
||||
purgedConfigs = lib.filterAttrs (_name: config: config.purgeOnChange) cfg.settings;
|
||||
|
||||
# WARNING: When changing this path, the next home-manager generation will
|
||||
# not find and the rules of the old generation that are subject to purging.
|
||||
purgedRulesConfigName = "purge-on-change";
|
||||
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
|
|
@ -185,93 +16,42 @@ in
|
|||
dawidsowa
|
||||
];
|
||||
|
||||
imports = [
|
||||
(lib.mkRemovedOptionModule [ "systemd" "user" "tmpfiles" "rules" ] ''
|
||||
It has been replaced by 'systemd.user.tmpfiles.settings'.
|
||||
'')
|
||||
];
|
||||
|
||||
options.systemd.user.tmpfiles.settings = lib.mkOption {
|
||||
options.systemd.user.tmpfiles.rules = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = [ "L /home/user/Documents - - - - /mnt/data/Documents" ];
|
||||
description = ''
|
||||
Declare systemd-tmpfiles rules to create, delete, and clean up volatile
|
||||
and temporary files and directories.
|
||||
|
||||
Even though the service is called `*tmp*files` you can also create
|
||||
persistent files.
|
||||
Rules for creating and cleaning up temporary files
|
||||
automatically. See
|
||||
{manpage}`tmpfiles.d(5)`
|
||||
for the exact format.
|
||||
'';
|
||||
example = {
|
||||
cache.rules."%C".d = {
|
||||
mode = "0755";
|
||||
user = "alice";
|
||||
group = "alice";
|
||||
age = "4 weeks";
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
type = attrsWith' "config-name" configSubmodule;
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
config = lib.mkIf (cfg.rules != [ ]) {
|
||||
assertions = [
|
||||
(lib.hm.assertions.assertPlatform "systemd.user.tmpfiles" pkgs lib.platforms.linux)
|
||||
];
|
||||
|
||||
(lib.mkIf pkgs.stdenv.hostPlatform.isLinux {
|
||||
# The activation script must be enabled unconditionally in order to
|
||||
# guarantee that the old rules are purged even if the new set of rules
|
||||
# is empty, i.e. `cfg.rulesToPurgeOnChange == [ ]`.
|
||||
home.activation.purgeTmpfiles = lib.hm.dag.entryAfter [ "writeBoundary" ] (
|
||||
let
|
||||
relativeXdgConfigHome = lib.strings.removePrefix "${config.home.homeDirectory}/" config.xdg.configHome;
|
||||
configPath = "home-files/${relativeXdgConfigHome}/${purgedRulesConfigName}";
|
||||
in
|
||||
''
|
||||
if [[ -v oldGenPath && -f $oldGenPath/${configPath} ]] &&
|
||||
diff -q $oldGenPath/${configPath} $newGenPath/${configPath} &>/dev/null; then
|
||||
verboseEcho "Purge old tmpfiles"
|
||||
run ${pkgs.systemd}/bin/systemd-tmpfiles --user --purge ''${DRY_RUN:+--dry-run} $oldGenPath/${configPath}
|
||||
fi
|
||||
''
|
||||
);
|
||||
})
|
||||
|
||||
(lib.mkIf (cfg.settings != { }) {
|
||||
assertions = [
|
||||
(lib.hm.assertions.assertPlatform "systemd.user.tmpfiles" pkgs lib.platforms.linux)
|
||||
];
|
||||
|
||||
warnings = lib.flatten (
|
||||
lib.mapAttrsToListRecursive (
|
||||
path: value:
|
||||
lib.optional
|
||||
(lib.last path == "argument" && lib.match ''.*\\([nrt]|x[0-9A-Fa-f]{2}).*'' value != null)
|
||||
''
|
||||
The '${lib.showAttrPath (modulePrefix ++ path)}' option
|
||||
appears to contain escape sequences, which will be escaped again.
|
||||
Unescape them if this is not intended. The assigned string is:
|
||||
"${value}"
|
||||
''
|
||||
) cfg.settings
|
||||
);
|
||||
|
||||
xdg.configFile = {
|
||||
"systemd/user/basic.target.wants/systemd-tmpfiles-setup.service".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-setup.service";
|
||||
"systemd/user/systemd-tmpfiles-setup.service".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-setup.service";
|
||||
"systemd/user/timers.target.wants/systemd-tmpfiles-clean.timer".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-clean.timer";
|
||||
"systemd/user/systemd-tmpfiles-clean.service".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-clean.service";
|
||||
}
|
||||
// lib.mapAttrs' (
|
||||
name: config: lib.nameValuePair (mkFileName name) (mkConfigFile name config.rules { })
|
||||
) nonPurgedConfigs
|
||||
// lib.optionalAttrs (purgedConfigs != { }) {
|
||||
${mkFileName purgedRulesConfigName} =
|
||||
let
|
||||
purgedConfigsMerged = lib.foldl' lib.recursiveUpdate { } (lib.attrValues purgedConfigs);
|
||||
in
|
||||
mkConfigFile purgedRulesConfigName purgedConfigsMerged.rules { suffix = [ ]; };
|
||||
xdg.configFile = {
|
||||
"user-tmpfiles.d/home-manager.conf" = {
|
||||
text = ''
|
||||
# This file is created automatically and should not be modified.
|
||||
# Please change the option ‘systemd.user.tmpfiles.rules’ instead.
|
||||
${lib.concatStringsSep "\n" cfg.rules}
|
||||
'';
|
||||
onChange = ''
|
||||
run ${pkgs.systemd}/bin/systemd-tmpfiles --user --remove --create ''${DRY_RUN:+--dry-run}
|
||||
'';
|
||||
};
|
||||
})
|
||||
|
||||
];
|
||||
"systemd/user/basic.target.wants/systemd-tmpfiles-setup.service".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-setup.service";
|
||||
"systemd/user/systemd-tmpfiles-setup.service".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-setup.service";
|
||||
"systemd/user/timers.target.wants/systemd-tmpfiles-clean.timer".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-clean.timer";
|
||||
"systemd/user/systemd-tmpfiles-clean.service".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-clean.service";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,194 +99,7 @@ in
|
|||
};
|
||||
|
||||
userSettings = mkOption {
|
||||
type = types.submodule {
|
||||
freeformType = tomlFormat.type;
|
||||
options = {
|
||||
after-startup-command = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [ ];
|
||||
description = ''
|
||||
A list of AeroSpace commands to execute immediately after the AeroSpace application starts.
|
||||
These commands are written to your `aerospace.toml` config file and are run after the `after-login-command` sequence.
|
||||
|
||||
A list of all available commands can be found at <https://nikitabobko.github.io/AeroSpace/commands>.
|
||||
|
||||
While this module checks for valid command names, using incorrect *arguments* can still cause issues.
|
||||
If AeroSpace is not behaving correctly after startup, check the logs for errors with `cat /tmp/aerospace.err.log`.
|
||||
'';
|
||||
example = [
|
||||
"exec-and-forget open -n /System/Applications/Utilities/Terminal.app"
|
||||
"layout tiles accordion"
|
||||
];
|
||||
};
|
||||
enable-normalization-flatten-containers = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''Containers that have only one child are "flattened".'';
|
||||
};
|
||||
enable-normalization-opposite-orientation-for-nested-containers = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Containers that nest into each other must have opposite orientations.";
|
||||
};
|
||||
accordion-padding = mkOption {
|
||||
type = types.int;
|
||||
default = 30;
|
||||
description = "Padding between windows in an accordion container.";
|
||||
};
|
||||
default-root-container-layout = mkOption {
|
||||
type = types.enum [
|
||||
"tiles"
|
||||
"accordion"
|
||||
];
|
||||
default = "tiles";
|
||||
description = "Default layout for the root container.";
|
||||
};
|
||||
default-root-container-orientation = mkOption {
|
||||
type = types.enum [
|
||||
"horizontal"
|
||||
"vertical"
|
||||
"auto"
|
||||
];
|
||||
default = "auto";
|
||||
description = "Default orientation for the root container.";
|
||||
};
|
||||
on-window-detected = mkOption {
|
||||
type = types.listOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
"if" = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
app-id = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = "The application ID to match (optional).";
|
||||
};
|
||||
workspace = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = "The workspace name to match (optional).";
|
||||
};
|
||||
window-title-regex-substring = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = "Substring to match in the window title (optional).";
|
||||
};
|
||||
app-name-regex-substring = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = "Regex substring to match the app name (optional).";
|
||||
};
|
||||
during-aerospace-startup = mkOption {
|
||||
type = with types; nullOr bool;
|
||||
default = null;
|
||||
description = "Whether to match during aerospace startup (optional).";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
description = "Conditions for detecting a window.";
|
||||
};
|
||||
check-further-callbacks = mkOption {
|
||||
type = with types; nullOr bool;
|
||||
default = null;
|
||||
description = "Whether to check further callbacks after this rule (optional).";
|
||||
};
|
||||
run = mkOption {
|
||||
type =
|
||||
with types;
|
||||
oneOf [
|
||||
str
|
||||
(listOf str)
|
||||
];
|
||||
example = [
|
||||
"move-node-to-workspace m"
|
||||
"resize-node"
|
||||
];
|
||||
description = "Commands to execute when the conditions match (required).";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = [ ];
|
||||
example = [
|
||||
{
|
||||
"if" = {
|
||||
app-id = "Another.Cool.App";
|
||||
workspace = "cool-workspace";
|
||||
window-title-regex-substring = "Title";
|
||||
app-name-regex-substring = "CoolApp";
|
||||
during-aerospace-startup = false;
|
||||
};
|
||||
check-further-callbacks = false;
|
||||
run = [
|
||||
"move-node-to-workspace m"
|
||||
"resize-node"
|
||||
];
|
||||
}
|
||||
];
|
||||
description = "Commands to run every time a new window is detected with optional conditions.";
|
||||
};
|
||||
workspace-to-monitor-force-assignment = mkOption {
|
||||
type =
|
||||
with types;
|
||||
nullOr (
|
||||
attrsOf (oneOf [
|
||||
int
|
||||
str
|
||||
(listOf str)
|
||||
])
|
||||
);
|
||||
default = null;
|
||||
description = ''
|
||||
Map workspaces to specific monitors.
|
||||
Left-hand side is the workspace name, and right-hand side is the monitor pattern.
|
||||
'';
|
||||
example = {
|
||||
"1" = 1; # First monitor from left to right.
|
||||
"2" = "main"; # Main monitor.
|
||||
"3" = "secondary"; # Secondary monitor (non-main).
|
||||
"4" = "built-in"; # Built-in display.
|
||||
"5" = "^built-in retina display$"; # Regex for the built-in retina display.
|
||||
"6" = [
|
||||
"secondary"
|
||||
"dell"
|
||||
]; # Match first pattern in the list.
|
||||
};
|
||||
};
|
||||
on-focus-changed = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [ ];
|
||||
example = [ "move-mouse monitor-lazy-center" ];
|
||||
description = "Commands to run every time focused window or workspace changes.";
|
||||
};
|
||||
on-focused-monitor-changed = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [ "move-mouse monitor-lazy-center" ];
|
||||
description = "Commands to run every time focused monitor changes.";
|
||||
};
|
||||
exec-on-workspace-change = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [ ];
|
||||
example = [
|
||||
"/bin/bash"
|
||||
"-c"
|
||||
"sketchybar --trigger aerospace_workspace_change FOCUSED_WORKSPACE=$AEROSPACE_FOCUSED_WORKSPACE"
|
||||
];
|
||||
description = "Commands to run every time workspace changes.";
|
||||
};
|
||||
key-mapping.preset = mkOption {
|
||||
type = types.enum [
|
||||
"qwerty"
|
||||
"dvorak"
|
||||
"colemak"
|
||||
];
|
||||
default = "qwerty";
|
||||
description = "Keymapping preset.";
|
||||
};
|
||||
};
|
||||
};
|
||||
inherit (tomlFormat) type;
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
|
|
|
|||
|
|
@ -153,6 +153,17 @@ let
|
|||
};
|
||||
};
|
||||
|
||||
completionModule = types.submodule {
|
||||
options = {
|
||||
body = mkOption {
|
||||
type = types.lines;
|
||||
description = ''
|
||||
The completion file's body.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
abbrModule = types.submodule {
|
||||
options = {
|
||||
expansion = mkOption {
|
||||
|
|
@ -556,6 +567,28 @@ in
|
|||
<https://fishshell.com/docs/current/cmds/function.html>.
|
||||
'';
|
||||
};
|
||||
|
||||
programs.fish.completions = mkOption {
|
||||
type = with types; attrsOf (either lines completionModule);
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
{
|
||||
my-prog = '''
|
||||
complete -c myprog -s o -l output
|
||||
''';
|
||||
|
||||
my-app = {
|
||||
body = '''
|
||||
complete -c myapp -s -v
|
||||
''';
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Custom fish completions. For more information see
|
||||
<https://fishshell.com/docs/current/completions.html>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (
|
||||
|
|
@ -734,6 +767,20 @@ in
|
|||
};
|
||||
}) cfg.functions;
|
||||
}
|
||||
{
|
||||
xdg.configFile = lib.mapAttrs' (name: def: {
|
||||
name = "fish/completions/${name}.fish";
|
||||
value = {
|
||||
source =
|
||||
let
|
||||
body = if isAttrs def then def.body else def;
|
||||
in
|
||||
fishIndent "${name}.fish" ''
|
||||
${lib.strings.removeSuffix "\n" body}
|
||||
'';
|
||||
};
|
||||
}) cfg.completions;
|
||||
}
|
||||
|
||||
# Each plugin gets a corresponding conf.d/plugin-NAME.fish file to load
|
||||
# in the paths and any initialization scripts.
|
||||
|
|
|
|||
|
|
@ -114,6 +114,24 @@ in
|
|||
defaultText = lib.literalMD "`true` if programs.ghostty.package is not null";
|
||||
};
|
||||
|
||||
systemd = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
options = {
|
||||
enable = lib.mkEnableOption "the Ghostty systemd user service" // {
|
||||
default = pkgs.stdenv.hostPlatform.isLinux;
|
||||
defaultText = lib.literalMD "`true` on Linux, `false` otherwise";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
description = ''
|
||||
Configuration for Ghostty's systemd integration.
|
||||
This enables additional speed and features.
|
||||
|
||||
See <https://ghostty.org/docs/linux/systemd> for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
enableBashIntegration = mkShellIntegrationOption (
|
||||
lib.hm.shell.mkBashIntegrationOption { inherit config; }
|
||||
);
|
||||
|
|
@ -195,6 +213,22 @@ in
|
|||
};
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.systemd.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.systemd.enable -> cfg.package != null;
|
||||
message = "programs.ghostty.systemd.enable cannot be true when programs.ghostty.package is null";
|
||||
}
|
||||
{
|
||||
assertion = cfg.systemd.enable -> pkgs.stdenv.hostPlatform.isLinux;
|
||||
message = "Ghostty systemd integration cannot be enabled for non-linux platforms";
|
||||
}
|
||||
];
|
||||
xdg.configFile."systemd/user/app-com.mitchellh.ghostty.service".source =
|
||||
"${cfg.package}/share/systemd/user/app-com.mitchellh.ghostty.service";
|
||||
dbus.packages = [ cfg.package ];
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.enableBashIntegration {
|
||||
# Make order 101 to be placed exactly after bash completions, as Ghostty
|
||||
# documentation suggests sourcing the script as soon as possible
|
||||
|
|
|
|||
|
|
@ -36,12 +36,14 @@ in
|
|||
|
||||
# Use `systemd-tmpfiles` since glab requires its configuration file to have
|
||||
# mode 0600.
|
||||
systemd.user.tmpfiles.settings.glab = lib.mkIf (cfg.settings != { }) {
|
||||
rules."${config.xdg.configHome}/glab-cli/config.yml" = {
|
||||
"C+$".argument = "${yaml.generate "glab-config" cfg.settings}";
|
||||
z.mode = "0600";
|
||||
};
|
||||
};
|
||||
systemd.user.tmpfiles.rules =
|
||||
let
|
||||
target = "${config.xdg.configHome}/glab-cli/config.yml";
|
||||
in
|
||||
lib.mkIf (cfg.settings != { }) [
|
||||
"C+ ${target} - - - - ${yaml.generate "glab-config" cfg.settings}"
|
||||
"z ${target} 0600"
|
||||
];
|
||||
|
||||
xdg.configFile."glab-cli/aliases.yml" = lib.mkIf (cfg.aliases != { }) {
|
||||
source = yaml.generate "glab-aliases" cfg.aliases;
|
||||
|
|
|
|||
|
|
@ -103,13 +103,11 @@ in
|
|||
'';
|
||||
|
||||
fishIntegration = ''
|
||||
function ${cfg.shellWrapperName}
|
||||
set -x LAZYGIT_NEW_DIR_FILE ${lazygitNewDirFilePath}
|
||||
command lazygit $argv
|
||||
if test -f $LAZYGIT_NEW_DIR_FILE
|
||||
cd (cat $LAZYGIT_NEW_DIR_FILE)
|
||||
rm -f $LAZYGIT_NEW_DIR_FILE
|
||||
end
|
||||
set -x LAZYGIT_NEW_DIR_FILE ${lazygitNewDirFilePath}
|
||||
command lazygit $argv
|
||||
if test -f $LAZYGIT_NEW_DIR_FILE
|
||||
cd (cat $LAZYGIT_NEW_DIR_FILE)
|
||||
rm -f $LAZYGIT_NEW_DIR_FILE
|
||||
end
|
||||
'';
|
||||
|
||||
|
|
|
|||
59
modules/programs/opkssh.nix
Normal file
59
modules/programs/opkssh.nix
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.programs.opkssh;
|
||||
|
||||
yamlFormat = pkgs.formats.yaml { };
|
||||
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.swarsel ];
|
||||
|
||||
options.programs.opkssh = {
|
||||
enable = lib.mkEnableOption "enable the OpenPubkey SSH client";
|
||||
|
||||
package = lib.mkPackageOption pkgs "opkssh" { nullable = true; };
|
||||
|
||||
settings = lib.mkOption {
|
||||
inherit (yamlFormat) type;
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
default_provider = "kanidm";
|
||||
|
||||
providers = [
|
||||
{
|
||||
alias = "kanidm";
|
||||
issuer = "https://idm.example.com/oauth2/openid/opkssh";
|
||||
client_id = "opkssh";
|
||||
scopes = "openid email profile";
|
||||
redirect_uris = [
|
||||
"http://localhost:3000/login-callback"
|
||||
"http://localhost:10001/login-callback"
|
||||
"http://localhost:11110/login-callback"
|
||||
];
|
||||
};
|
||||
];
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Configuration written to {file}`$HOME/.opk/config.yml`.
|
||||
See <https://github.com/openpubkey/opkssh/blob/main/docs/config.md#client-config-opkconfigyml>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||
|
||||
home.file."${config.home.homeDirectory}/.opk/config.yml" = lib.mkIf (cfg.settings != { }) {
|
||||
source = yamlFormat.generate "opkssh-config-${config.home.username}.yml" cfg.settings;
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
|
@ -7,7 +7,10 @@
|
|||
|
||||
let
|
||||
cfg = config.programs.superfile;
|
||||
|
||||
tomlFormat = pkgs.formats.toml { };
|
||||
jsonFormat = pkgs.formats.json { };
|
||||
|
||||
inherit (pkgs.stdenv.hostPlatform) isDarwin;
|
||||
inherit (lib)
|
||||
literalExpression
|
||||
|
|
@ -23,6 +26,29 @@ let
|
|||
types
|
||||
hm
|
||||
;
|
||||
|
||||
pinnedFolderModule = types.submodule {
|
||||
freeformType = jsonFormat.type;
|
||||
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "Nix Store";
|
||||
description = ''
|
||||
Name that will be shown.
|
||||
'';
|
||||
};
|
||||
|
||||
location = mkOption {
|
||||
type = types.path;
|
||||
example = "/nix/store";
|
||||
description = ''
|
||||
Location of the pinned entry.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ hm.maintainers.LucasWagler ];
|
||||
|
|
@ -106,11 +132,38 @@ in
|
|||
};
|
||||
'';
|
||||
};
|
||||
|
||||
firstUseCheck = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Enables the first time use popup.
|
||||
'';
|
||||
};
|
||||
|
||||
pinnedFolders = mkOption {
|
||||
type = types.listOf pinnedFolderModule;
|
||||
default = [ ];
|
||||
example = literalExpression ''
|
||||
[
|
||||
{
|
||||
name = "Nix Store";
|
||||
location = "/nix/store";
|
||||
}
|
||||
];
|
||||
'';
|
||||
description = ''
|
||||
Entries that get added to the pinned panel.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
enableXdgConfig = !isDarwin || config.xdg.enable;
|
||||
baseConfigPath = if enableXdgConfig then "superfile" else "Library/Application Support/superfile";
|
||||
baseDataPath = if enableXdgConfig then "superfile" else "Library/Application Support/superfile";
|
||||
|
||||
themeSetting =
|
||||
if (!(cfg.settings ? theme) && cfg.themes != { }) then
|
||||
{
|
||||
|
|
@ -118,7 +171,6 @@ in
|
|||
}
|
||||
else
|
||||
{ };
|
||||
baseConfigPath = if enableXdgConfig then "superfile" else "Library/Application Support/superfile";
|
||||
configFile = mkIf (cfg.settings != { }) {
|
||||
"${baseConfigPath}/config.toml".source = tomlFormat.generate "superfile-config.toml" (
|
||||
recursiveUpdate themeSetting cfg.settings
|
||||
|
|
@ -139,24 +191,48 @@ in
|
|||
(tomlFormat.generate "superfile-theme-${name}.toml" value);
|
||||
}
|
||||
) cfg.themes;
|
||||
|
||||
firstUseCheckFile = mkIf (!cfg.firstUseCheck) { "${baseDataPath}/firstUseCheck".text = ""; };
|
||||
pinnedFile = mkIf (cfg.pinnedFolders != [ ]) {
|
||||
"${baseDataPath}/pinned.json".source = jsonFormat.generate "pinned.json" cfg.pinnedFolders;
|
||||
};
|
||||
|
||||
files = mkMerge [
|
||||
configFile
|
||||
hotkeysFile
|
||||
themeFiles
|
||||
|
||||
firstUseCheckFile
|
||||
pinnedFile
|
||||
];
|
||||
configFiles = mkMerge [
|
||||
configFile
|
||||
hotkeysFile
|
||||
themeFiles
|
||||
];
|
||||
dataFiles = mkMerge [
|
||||
firstUseCheckFile
|
||||
pinnedFile
|
||||
];
|
||||
in
|
||||
mkIf cfg.enable {
|
||||
home.packages = mkIf (cfg.package != null) (
|
||||
[ cfg.package ]
|
||||
++ optional (
|
||||
cfg.metadataPackage != null && cfg.settings ? metadata && cfg.settings.metadata
|
||||
) cfg.metadataPackage
|
||||
++ optional (
|
||||
cfg.zoxidePackage != null && cfg.settings ? zoxide_support && cfg.settings.zoxide_support
|
||||
) cfg.zoxidePackage
|
||||
);
|
||||
home = {
|
||||
packages = mkIf (cfg.package != null) (
|
||||
[ cfg.package ]
|
||||
++ optional (
|
||||
cfg.metadataPackage != null && cfg.settings ? metadata && cfg.settings.metadata
|
||||
) cfg.metadataPackage
|
||||
++ optional (
|
||||
cfg.zoxidePackage != null && cfg.settings ? zoxide_support && cfg.settings.zoxide_support
|
||||
) cfg.zoxidePackage
|
||||
);
|
||||
|
||||
xdg.configFile = mkIf enableXdgConfig configFiles;
|
||||
home.file = mkIf (!enableXdgConfig) configFiles;
|
||||
file = mkIf (!enableXdgConfig) files;
|
||||
};
|
||||
|
||||
xdg = {
|
||||
configFile = mkIf enableXdgConfig configFiles;
|
||||
dataFile = mkIf enableXdgConfig dataFiles;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,7 +224,6 @@ in
|
|||
Documentation = [ "https://docs.vicinae.com" ];
|
||||
After = [ cfg.systemd.target ];
|
||||
PartOf = [ cfg.systemd.target ];
|
||||
BindsTo = [ cfg.systemd.target ];
|
||||
};
|
||||
Service = {
|
||||
EnvironmentFile = pkgs.writeText "vicinae-env" ''
|
||||
|
|
|
|||
|
|
@ -459,7 +459,7 @@ in
|
|||
existing_profiles=$(jq '.userDataProfiles // [] | map({ (.name): .location }) | add // {}' "$file")
|
||||
|
||||
for profile in "''${profiles[@]}"; do
|
||||
if [[ "$(echo $existing_profiles | jq --arg profile $profile 'has ($profile)')" != "true" ]] || [[ "$(echo $existing_profiles | jq --arg profile $profile 'has ($profile)')" == "true" && "$(echo $existing_profiles | jq --arg profile $profile '.[$profile]')" != "\"$profile\"" ]]; then
|
||||
if [[ "$(echo $existing_profiles | jq --arg profile "$profile" 'has ($profile)')" != "true" ]] || [[ "$(echo $existing_profiles | jq --arg profile "$profile" 'has ($profile)')" == "true" && "$(echo $existing_profiles | jq --arg profile "$profile" '.[$profile]')" != "\"$profile\"" ]]; then
|
||||
file_write="$file_write$([ "$file_write" != "" ] && echo "...")$profile"
|
||||
fi
|
||||
done
|
||||
|
|
|
|||
74
modules/services/tomat.nix
Normal file
74
modules/services/tomat.nix
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.tomat;
|
||||
tomlFormat = pkgs.formats.toml { };
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ jolars ];
|
||||
|
||||
options.services.tomat = {
|
||||
enable = lib.mkEnableOption "Tomat Pomodoro server";
|
||||
|
||||
package = lib.mkPackageOption pkgs "tomat" { };
|
||||
|
||||
settings = lib.mkOption {
|
||||
type = lib.types.submodule { freeformType = tomlFormat.type; };
|
||||
|
||||
default = { };
|
||||
|
||||
example = {
|
||||
timer = {
|
||||
work = 25;
|
||||
break = 5;
|
||||
auto_advance = false;
|
||||
};
|
||||
|
||||
sound = {
|
||||
enabled = true;
|
||||
};
|
||||
|
||||
notification = {
|
||||
enabled = true;
|
||||
};
|
||||
};
|
||||
|
||||
description = ''
|
||||
Tomat configuration.
|
||||
See <https://github.com/jolars/tomat/blob/main/docs/configuration.md> for supported values.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
xdg.configFile = {
|
||||
"tomat/config.toml" = lib.mkIf (cfg.settings != { }) {
|
||||
source = tomlFormat.generate "tomat-config.toml" cfg.settings;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.user.services.tomat = {
|
||||
Unit = {
|
||||
Description = "Tomat Pomodoro server";
|
||||
After = [ "graphical.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = "${lib.getExe cfg.package} daemon run";
|
||||
Restart = "always";
|
||||
RestartSec = 5;
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "default.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -203,7 +203,6 @@ import nmtSrc {
|
|||
./modules/misc/numlock
|
||||
./modules/misc/pam
|
||||
./modules/misc/qt
|
||||
./modules/misc/tmpfiles
|
||||
./modules/misc/xdg/linux.nix
|
||||
./modules/misc/xsession
|
||||
./modules/systemd
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@ in
|
|||
uid = 1000;
|
||||
};
|
||||
|
||||
systemd.tmpfiles.settings.age.rules."/home/alice/age-key".f = {
|
||||
mode = "400";
|
||||
user = "alice";
|
||||
group = "users";
|
||||
argument = ageKey;
|
||||
};
|
||||
systemd.tmpfiles.rules = [
|
||||
"f /home/alice/age-key 400 alice users - ${ageKey}"
|
||||
];
|
||||
|
||||
home-manager.users.alice =
|
||||
{ config, ... }:
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
imports = [ ./common-stubs.nix ];
|
||||
|
||||
systemd.user.tmpfiles.settings = {
|
||||
cache.rules."%C".d.age = "4 weeks";
|
||||
myTool.rules."%h/.config/myTool.conf"."f+" = {
|
||||
mode = "0644";
|
||||
user = "alice";
|
||||
group = "users";
|
||||
argument = "my unescaped config";
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertPathNotExists home-files/.config/user-tmpfiles.d/home-manager-purge-on-change.conf
|
||||
|
||||
cacheRulesFile=home-files/.config/user-tmpfiles.d/home-manager-cache.conf
|
||||
assertFileExists $cacheRulesFile
|
||||
assertFileRegex $cacheRulesFile "^'d' '%C' '-' '-' '-' '4 weeks' $"
|
||||
|
||||
myToolRulesFile=home-files/.config/user-tmpfiles.d/home-manager-myTool.conf
|
||||
assertFileExists $myToolRulesFile
|
||||
assertFileRegex $myToolRulesFile \
|
||||
"^'f+' '%h/.config/myTool.conf' '0644' 'alice' 'users' '-' my\\\\x20unescaped\\\\x20config$"
|
||||
'';
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
test.stubs.systemd.outPath = null;
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
tmpfiles-no-rules = ./no-rules.nix;
|
||||
tmpfiles-basic-rules = ./basic-rules.nix;
|
||||
tmpfiles-rules-with-purging = ./rules-with-purging.nix;
|
||||
|
||||
tmpfiles-escaped-argument-warning = ./escaped-argument-warning.nix;
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
imports = [ ./common-stubs.nix ];
|
||||
|
||||
systemd.user.tmpfiles.settings.foo.rules.path.f.argument = "my\\x20unescaped\\x20config";
|
||||
|
||||
test.asserts.warnings.expected = [
|
||||
''
|
||||
The 'systemd.user.tmpfiles.settings.foo.rules.path.f.argument' option
|
||||
appears to contain escape sequences, which will be escaped again.
|
||||
Unescape them if this is not intended. The assigned string is:
|
||||
"my\x20unescaped\x20config"
|
||||
''
|
||||
];
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
imports = [ ./common-stubs.nix ];
|
||||
|
||||
systemd.user.tmpfiles.settings = { };
|
||||
|
||||
nmt.script = ''
|
||||
assertPathNotExists home-files/.config/user-tmpfiles.d/
|
||||
'';
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
{
|
||||
imports = [ ./common-stubs.nix ];
|
||||
|
||||
systemd.user.tmpfiles.settings = {
|
||||
cache.rules."%C".d.age = "4 weeks";
|
||||
myTool = {
|
||||
rules = {
|
||||
"%h/.config/myTool.conf"."f+".argument = "my_config";
|
||||
"%h/.config/myToolPurged.conf"."f+$".argument = "my_config_purged";
|
||||
};
|
||||
purgeOnChange = true;
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
cacheRulesFile=home-files/.config/user-tmpfiles.d/home-manager-cache.conf
|
||||
assertFileExists $cacheRulesFile
|
||||
assertFileRegex $cacheRulesFile "^'d' '%C' '-' '-' '-' '4 weeks' $"
|
||||
|
||||
assertPathNotExists home-files/.config/user-tmpfiles.d/home-manager-myTool.conf
|
||||
myToolRulesFile=home-files/.config/user-tmpfiles.d/home-manager-purge-on-change.conf
|
||||
assertFileExists $myToolRulesFile
|
||||
assertFileRegex $myToolRulesFile \
|
||||
"^'f+' '%h/.config/myTool.conf' '-' '-' '-' '-' my_config$"
|
||||
assertFileRegex $myToolRulesFile \
|
||||
"^'f+$' '%h/.config/myToolPurged.conf' '-' '-' '-' '-' my_config_purged$"
|
||||
'';
|
||||
}
|
||||
|
|
@ -1,14 +1,3 @@
|
|||
accordion-padding = 30
|
||||
after-startup-command = []
|
||||
default-root-container-layout = "tiles"
|
||||
default-root-container-orientation = "auto"
|
||||
enable-normalization-flatten-containers = true
|
||||
enable-normalization-opposite-orientation-for-nested-containers = true
|
||||
exec-on-workspace-change = []
|
||||
on-focus-changed = []
|
||||
on-focused-monitor-changed = ["move-mouse monitor-lazy-center"]
|
||||
on-window-detected = []
|
||||
|
||||
[gaps.outer]
|
||||
bottom = 8
|
||||
left = 8
|
||||
|
|
|
|||
|
|
@ -1,14 +1,4 @@
|
|||
accordion-padding = 30
|
||||
after-login-command = []
|
||||
after-startup-command = []
|
||||
default-root-container-layout = "tiles"
|
||||
default-root-container-orientation = "auto"
|
||||
enable-normalization-flatten-containers = true
|
||||
enable-normalization-opposite-orientation-for-nested-containers = true
|
||||
exec-on-workspace-change = []
|
||||
on-focus-changed = []
|
||||
on-focused-monitor-changed = ["move-mouse monitor-lazy-center"]
|
||||
on-window-detected = []
|
||||
start-at-login = false
|
||||
|
||||
[gaps.outer]
|
||||
|
|
@ -17,9 +7,6 @@ left = 8
|
|||
right = 8
|
||||
top = 8
|
||||
|
||||
[key-mapping]
|
||||
preset = "qwerty"
|
||||
|
||||
[mode.main.binding]
|
||||
alt-h = "focus left"
|
||||
alt-j = "focus down"
|
||||
|
|
|
|||
45
tests/modules/programs/fish/completions.nix
Normal file
45
tests/modules/programs/fish/completions.nix
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
{ lib, pkgs, ... }:
|
||||
let
|
||||
myProg = pkgs.writeText "my-prog.fish" ''
|
||||
complete -c myprog -s o -l output
|
||||
'';
|
||||
|
||||
myApp = pkgs.writeText "my-app.fish" ''
|
||||
complete -c myapp -s -v
|
||||
'';
|
||||
in
|
||||
{
|
||||
config = {
|
||||
programs.fish = {
|
||||
enable = true;
|
||||
|
||||
completions = {
|
||||
my-prog = ''
|
||||
complete -c myprog -s o -l output
|
||||
'';
|
||||
my-app = {
|
||||
body = ''
|
||||
complete -c myapp -s -v
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
xdg.dataFile."fish/home-manager_generated_completions".source = lib.mkForce (
|
||||
builtins.toFile "empty" ""
|
||||
);
|
||||
|
||||
nmt = {
|
||||
description = "if fish.completions is set, check file exists and contents match";
|
||||
script = ''
|
||||
assertFileExists home-files/.config/fish/completions/my-prog.fish
|
||||
echo ${myProg}
|
||||
assertFileContent home-files/.config/fish/completions/my-prog.fish ${myProg}
|
||||
|
||||
assertFileExists home-files/.config/fish/completions/my-app.fish
|
||||
echo ${myApp}
|
||||
assertFileContent home-files/.config/fish/completions/my-app.fish ${myApp}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
fish-abbrs = ./abbrs.nix;
|
||||
fish-format-scripts = ./format-scripts.nix;
|
||||
fish-functions = ./functions.nix;
|
||||
fish-completions = ./completions.nix;
|
||||
fish-no-functions = ./no-functions.nix;
|
||||
fish-plugins = ./plugins.nix;
|
||||
fish-manpage = ./manpage.nix;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
{ config, ... }:
|
||||
{
|
||||
programs.ghostty.enable = true;
|
||||
programs.ghostty = {
|
||||
enable = true;
|
||||
package = config.lib.test.mkStubPackage { outPath = null; };
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertPathNotExists home-files/.config/ghostty/config
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
{
|
||||
programs.ghostty = {
|
||||
enable = true;
|
||||
package = config.lib.test.mkStubPackage { };
|
||||
package = config.lib.test.mkStubPackage { outPath = null; };
|
||||
|
||||
settings = {
|
||||
theme = "catppuccin-mocha";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
{ config, ... }:
|
||||
{
|
||||
programs.ghostty = {
|
||||
enable = true;
|
||||
package = config.lib.test.mkStubPackage { outPath = null; };
|
||||
|
||||
themes = {
|
||||
catppuccin-mocha = {
|
||||
|
|
|
|||
3
tests/modules/programs/lazygit/default.nix
Normal file
3
tests/modules/programs/lazygit/default.nix
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
lazygit-fish-integration-enabled = ./fish-integration-enabled.nix;
|
||||
}
|
||||
18
tests/modules/programs/lazygit/fish-integration-enabled.nix
Normal file
18
tests/modules/programs/lazygit/fish-integration-enabled.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{ config, ... }:
|
||||
|
||||
{
|
||||
programs.fish.enable = true;
|
||||
|
||||
home.preferXdgDirectories = false;
|
||||
|
||||
programs.lazygit = {
|
||||
enable = true;
|
||||
shellWrapperName = "lg";
|
||||
enableFishIntegration = true;
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileContent home-files/.config/fish/functions/${config.programs.lazygit.shellWrapperName}.fish \
|
||||
${./fish-integration-expected.fish}
|
||||
'';
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
function lg
|
||||
set -x LAZYGIT_NEW_DIR_FILE ~/.lazygit/newdir
|
||||
command lazygit $argv
|
||||
if test -f $LAZYGIT_NEW_DIR_FILE
|
||||
cd (cat $LAZYGIT_NEW_DIR_FILE)
|
||||
rm -f $LAZYGIT_NEW_DIR_FILE
|
||||
end
|
||||
end
|
||||
3
tests/modules/programs/opkssh/default.nix
Normal file
3
tests/modules/programs/opkssh/default.nix
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
opkssh-basic-config = ./opkssh-basic-config.nix;
|
||||
}
|
||||
42
tests/modules/programs/opkssh/opkssh-basic-config.nix
Normal file
42
tests/modules/programs/opkssh/opkssh-basic-config.nix
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
_: {
|
||||
programs.opkssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
default_provider = "test-provider";
|
||||
providers = [
|
||||
{
|
||||
alias = "test-provider";
|
||||
issuer = "https://test.domain/oauth2/openid/opkssh";
|
||||
client_id = "opkssh";
|
||||
scopes = "openid email profile";
|
||||
redirect_uris = [
|
||||
"http://localhost:3000/login-callback"
|
||||
"http://localhost:10001/login-callback"
|
||||
"http://localhost:11110/login-callback"
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
configFile=home-files/.opk/config.yml
|
||||
|
||||
assertFileExists "$configFile"
|
||||
|
||||
configFileNormalized="$(normalizeStorePaths "$configFile")"
|
||||
|
||||
assertFileContent "$configFileNormalized" ${builtins.toFile "expected.service" ''
|
||||
default_provider: test-provider
|
||||
providers:
|
||||
- alias: test-provider
|
||||
client_id: opkssh
|
||||
issuer: https://test.domain/oauth2/openid/opkssh
|
||||
redirect_uris:
|
||||
- http://localhost:3000/login-callback
|
||||
- http://localhost:10001/login-callback
|
||||
- http://localhost:11110/login-callback
|
||||
scopes: openid email profile
|
||||
''}
|
||||
'';
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
{
|
||||
"location": "/nix/store",
|
||||
"name": "Nix Store"
|
||||
}
|
||||
]
|
||||
|
|
@ -53,6 +53,13 @@
|
|||
];
|
||||
};
|
||||
};
|
||||
firstUseCheck = false;
|
||||
pinnedFolders = [
|
||||
{
|
||||
name = "Nix Store";
|
||||
location = "/nix/store";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
nmt.script =
|
||||
|
|
@ -60,6 +67,10 @@
|
|||
configSubPath =
|
||||
if !pkgs.stdenv.isDarwin then ".config/superfile" else "Library/Application Support/superfile";
|
||||
configBasePath = "home-files/" + configSubPath;
|
||||
|
||||
dataSubPath =
|
||||
if !pkgs.stdenv.isDarwin then ".local/share/superfile" else "Library/Application Support/superfile";
|
||||
dataBasePath = "home-files/" + dataSubPath;
|
||||
in
|
||||
''
|
||||
assertFileExists "${configBasePath}/config.toml"
|
||||
|
|
@ -82,5 +93,10 @@
|
|||
assertFileContent \
|
||||
"${configBasePath}/theme/test2.toml" \
|
||||
${./example-theme2-expected.toml}
|
||||
assertFileExists "${dataBasePath}/firstUseCheck"
|
||||
assertFileExists "${dataBasePath}/pinned.json"
|
||||
assertFileContent \
|
||||
"${dataBasePath}/pinned.json" \
|
||||
${./example-pinned-folders.json}
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
5
tests/modules/services/tomat/default.nix
Normal file
5
tests/modules/services/tomat/default.nix
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{ lib, pkgs, ... }:
|
||||
|
||||
lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux {
|
||||
tomat-service = ./tomat.nix;
|
||||
}
|
||||
3
tests/modules/services/tomat/expected-config.toml
Normal file
3
tests/modules/services/tomat/expected-config.toml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[timer]
|
||||
break = 10
|
||||
work = 60
|
||||
11
tests/modules/services/tomat/expected.service
Normal file
11
tests/modules/services/tomat/expected.service
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[Install]
|
||||
WantedBy=default.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@tomat@/bin/tomat daemon run
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Unit]
|
||||
After=graphical.target
|
||||
Description=Tomat Pomodoro server
|
||||
25
tests/modules/services/tomat/tomat.nix
Normal file
25
tests/modules/services/tomat/tomat.nix
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
services.tomat = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
timer = {
|
||||
break = 10;
|
||||
work = 60;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script =
|
||||
let
|
||||
serviceFile = "home-files/.config/systemd/user/tomat.service";
|
||||
configFile = "home-files/.config/tomat/config.toml";
|
||||
in
|
||||
''
|
||||
assertFileExists "${serviceFile}"
|
||||
assertFileExists "${configFile}"
|
||||
|
||||
assertFileContent "${serviceFile}" ${./expected.service}
|
||||
assertFileContent "${configFile}" ${./expected-config.toml}
|
||||
'';
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue