mirror of
https://github.com/nix-community/home-manager.git
synced 2025-11-08 11:36:05 +01:00
Compare commits
6 commits
af119feb17
...
2907788315
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2907788315 | ||
|
|
ba15db2a15 | ||
|
|
8929c5f3bc | ||
|
|
d375dfc1ff | ||
|
|
432bc8a5da | ||
|
|
7f619d2a72 |
16 changed files with 255 additions and 219 deletions
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.
|
||||
'';
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
'';
|
||||
|
||||
|
|
|
|||
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" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
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
|
||||
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