diff --git a/.envrc b/.envrc
index af0cc93..3550a30 100644
--- a/.envrc
+++ b/.envrc
@@ -1,2 +1 @@
-#!/usr/bin/env bash
use flake
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
deleted file mode 100644
index 5ace460..0000000
--- a/.github/dependabot.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-version: 2
-updates:
- - package-ecosystem: "github-actions"
- directory: "/"
- schedule:
- interval: "weekly"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index e259464..0000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-name: CI
-on:
- push:
- branches:
- - main
- pull_request:
- workflow_dispatch:
-permissions:
- contents: read
-jobs:
- ci:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v6
- - name: Install Nix
- uses: cachix/install-nix-action@v31
- with:
- extra_nix_config: |
- experimental-features = nix-command flakes
- access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- - name: Run checks
- run: nix flake check
diff --git a/.github/workflows/update-flake-lock.yml b/.github/workflows/update-flake-lock.yml
deleted file mode 100644
index 11a1391..0000000
--- a/.github/workflows/update-flake-lock.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-name: update-flake-lock
-on:
- workflow_dispatch:
- schedule:
- - cron: "0 0 * * 5"
-permissions:
- contents: write
- pull-requests: write
-jobs:
- lockfile:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout repository
- uses: actions/checkout@v6
- - name: Install Nix
- uses: cachix/install-nix-action@v31
- with:
- nix_path: nixpkgs=channel:nixos-unstable
- - name: Update flake.lock
- uses: DeterminateSystems/update-flake-lock@v28
- with:
- sign-commits: true
- gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
- gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }}
diff --git a/.tangled/workflows/checks.yml b/.tangled/workflows/checks.yml
new file mode 100644
index 0000000..f39603d
--- /dev/null
+++ b/.tangled/workflows/checks.yml
@@ -0,0 +1,14 @@
+when:
+ - event: ["push", "manual"]
+ branch: ["main"]
+ - event: ["pull_request"]
+ branch: ["main"]
+engine: "nixery"
+dependencies:
+ nixpkgs:
+ - nix
+steps:
+ - name: "Run checks"
+ command: |
+ set -euo pipefail
+ nix flake check
diff --git a/.tangled/workflows/update-flake-lock.yml b/.tangled/workflows/update-flake-lock.yml
new file mode 100644
index 0000000..5135685
--- /dev/null
+++ b/.tangled/workflows/update-flake-lock.yml
@@ -0,0 +1,25 @@
+when:
+ - event: ["manual"]
+engine: "nixery"
+dependencies:
+ nixpkgs:
+ - git
+ - nix
+steps:
+ - name: "Update flake.lock"
+ command: |
+ set -euo pipefail
+
+ git config user.name "spindle"
+ git config user.email "spindle@zezura.xyz"
+
+ nix flake update
+
+ if git diff --quiet -- flake.lock; then
+ echo "flake.lock is already up to date"
+ exit 0
+ fi
+
+ git add flake.lock
+ git commit -m "flake.lock: update"
+ git push origin "HEAD:${TANGLED_REPO_DEFAULT_BRANCH:-main}"
diff --git a/README.md b/README.md
index 6e17dba..6602c7e 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,16 @@
-

+

# hylix
Hyprland configuration framework.
+ [](https://github.com/adam01110/hylix)
+
[](https://nixos.wiki/wiki/Flakes)
[](https://hyprland.org)
- [Overview](#overview) — [Modules](#modules) — [Usage](#usage) — [Development](#development) — [Notes](#notes)
+ [Overview](#overview) - [Usage](#usage) - [Modules](#modules)
## Overview
@@ -17,116 +19,66 @@ Define your Hyprland configuration in Nix. Each domain — settings, keybinds, m
This is a refactored fork of [`karol-broda/nixhypr`](https://github.com/karol-broda/nixhypr)
-## Modules
-
-All options live under `programs.hylix.*`.
-
-| Nix option | Lua function | What it configures |
-|---|---|---|
-| `settings` | `hl.config(...)` | Freeform Hyprland settings table |
-| `env` | `hl.env(...)` | Environment variables |
-| `monitors` | `hl.monitor(...)` | Monitor outputs, resolution, position, scale |
-| `animations.curves` | `hl.curve(...)` | Named bezier and spring curves |
-| `animations.animations` | `hl.animation(...)` | Animation definitions |
-| `devices` | `hl.device(...)` | Input device configuration |
-| `permissions` | `hl.permission(...)` | Permission rules (binary, mode, type) |
-| `gestures` | `hl.gesture(...)` | Touch gesture bindings |
-| `binds` / `bindGroups` | `hl.bind(...)` | Keybindings with optional grouping |
-| `rules.window` | `hl.window_rule(...)` | Window matching rules |
-| `rules.workspace` | `hl.workspace_rule(...)` | Workspace rules |
-| `rules.layer` | `hl.layer_rule(...)` | Layer surface rules |
-| `autostart` | `hl.exec_cmd(...)` | Startup commands |
-| `extraLua` / `extraLuaSnippets` | *(raw append)* | Arbitrary Lua code |
-
-The generated output respects a deterministic ordering: settings first, then env, monitors, curves, animations, devices, permissions, gestures, binds, window/workspace/layer rules, autostart, and finally extra Lua snippets.
-
## Usage
-Add the flake as an input and import either the generic module set or the Home Manager wrapper.
-
-### Via Home Manager
+Add the flake as an input:
```nix
{
- inputs = {
- nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
- hylix.url = "github:adam01110/hylix";
- };
+ inputs.hylix.url = "github:adam01110/hylix";
}
```
+Then import the Home Manager module and set the pieces you care about:
+
```nix
{
- imports = [ hylix.homeManagerModules.default ];
+ hylix,
+ ...
+}: {
+ imports = [hylix.homeManagerModules.default];
programs.hylix = {
enable = true;
- settings = {
- decoration = {
- blur = {
- enabled = true;
- size = 5;
- };
- };
+ settings.general = {
+ gaps_in = 2;
+ gaps_out = 6;
};
- monitors = [
- { name = "DP-1"; width = 2560; height = 1440; }
- { name = "HDMI-A-1"; width = 1920; height = 1080; }
- ];
-
binds = [
- { keys = [ "SUPER" "q" ]; action = "window.close"; }
- { keys = [ "SUPER" "Return" ]; exec = "foot"; }
- ];
-
- autostart = [
- "waybar"
- "mako"
+ {
+ keys = ["SUPER" "Return"];
+ exec = "foot";
+ }
];
};
}
```
-If Hyprland's own Home Manager module is enabled, the generated Lua is injected into `extraConfig`. Otherwise it is written to `xdg.configFile."hypr/hyprland.lua"`.
+If `wayland.windowManager.hyprland.enable` is already enabled in Home Manager, hylix puts the generated Lua in `wayland.windowManager.hyprland.extraConfig`. Otherwise it writes `~/.config/hypr/hyprland.lua` through `xdg.configFile`.
-### Without Home Manager
+For lower-level use, the generic module is exported as `hylix.modules.generic.hylix` and the generated text is exposed at `config.programs.hylix._generatedConfig`.
-Use the generic module set directly:
-
-```nix
-{
- flake.modules.generic.hylix = {
- programs.hylix.settings = {
- general = {
- gaps_in = 2;
- gaps_out = 4;
- };
- };
- };
-}
-```
-
-## Development
-
-From the repository root:
-
-```bash
-# Inspect flake outputs
-nix flake show
-
-# Run CI-equivalent checks
-nix flake check
-
-# Format the repository
-nix fmt
-```
-
-Formatting is wired through `treefmt-nix` using `alejandra`, `deadnix`, `statix`, and `keep-sorted`.
+## Modules
-## Notes
+All options live under `programs.hylix.*`.
-- This is a framework, not a standalone configuration. It provides the Nix options and serialisation logic; you provide the values.
-- The Lua output targets Hyprland's Lua config API (`hl.*` functions). Make sure your Hyprland build supports it.
-- `binds` and `bindGroups` both produce the same `hl.bind(...)` output — groups are a convenience for organising related keybinds by category.
+| Option | Lua output | What it configures |
+| --- | --- | --- |
+| `settings` | `hl.config(...)` | Freeform Hyprland settings |
+| `env` | `hl.env(...)` | Environment variables |
+| `monitors` | `hl.monitor(...)` | Outputs, modes, positions, and scale |
+| `devices` | `hl.device(...)` | Input device tables |
+| `animations.curves` | `hl.curve(...)` | Named bezier and spring curves |
+| `animations.animations` | `hl.animation(...)` | Animation rules |
+| `rules.window` | `hl.window_rule(...)` | Window matching rules |
+| `rules.workspace` | `hl.workspace_rule(...)` | Workspace rules |
+| `rules.layer` | `hl.layer_rule(...)` | Layer surface rules |
+| `permissions` | `hl.permission(...)` | Permission prompts and allow/deny rules |
+| `gestures` | `hl.gesture(...)` | Touch gesture bindings |
+| `binds` / `bindGroups` | `hl.bind(...)` | Keybinds, with optional categories |
+| `autostart` | `hl.exec_cmd(...)` | Startup commands |
+| `notifications` | `hl.notification.create(...)` | Startup notifications |
+| `events` | `hl.on(...)` | Hyprland event hooks |
+| `extraLua` / `extraLuaSnippets` | raw append | Anything the module options do not cover |
diff --git a/lib/default.nix b/lib/default.nix
index f308088..6c170e9 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -9,6 +9,7 @@ in {
mkHylixAnimationLineWithCurves
mkHylixAnimationLines
mkHylixAnimationLinesWithCurves
+ mkHylixAutostartLine
mkHylixBind
mkHylixBindGroup
mkHylixBindLine
@@ -16,7 +17,15 @@ in {
mkHylixCurveLine
mkHylixCurveLines
mkHylixDispatcher
+ mkHylixEnvLine
+ mkHylixEnvLines
+ mkHylixEventLine
+ mkHylixGeneratedConfig
mkHylixGroupedBinds
+ mkHylixLines
+ mkHylixLuaCall
+ mkHylixLuaCallLines
+ mkHylixLuaValueCall
mkHylixMonitorLine
mkHylixRuleLine
# keep-sorted end
diff --git a/lib/modules.nix b/lib/modules.nix
index 080ad7f..f1ab841 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -1,218 +1,10 @@
{lib}: let
- inherit
- (builtins)
- # keep-sorted start
- filter
- fromJSON
- hasAttr
- isString
- # keep-sorted end
- ;
- inherit
- (lib)
- # keep-sorted start
- concatMap
- concatStringsSep
- filterAttrs
- foldl'
- mapAttrsToList
- optionalAttrs
- replaceStrings
- # keep-sorted end
- ;
-
- cleanAttrs = filterAttrs (_: value: value != null);
-
- sanitizeCurveName = replaceStrings [":" "/" " " "-" "."] ["_" "_" "_" "_" "_"];
-
- mkDerivedSpringName = anim: "hylix_${sanitizeCurveName anim.leaf}_${sanitizeCurveName anim.spring}";
-
- scaleSpringForSpeed = speed: curve: let
- timeScale = speed / 10.0;
- in
- curve
- // optionalAttrs ((curve.stiffness or null) != null) {
- stiffness = curve.stiffness / (timeScale * timeScale);
- }
- // optionalAttrs ((curve.dampening or null) != null) {
- dampening = curve.dampening / timeScale;
- };
-in rec {
- mkHylixBind = description: keys: dispatcher:
- {
- inherit
- # keep-sorted start
- description
- keys
- # keep-sorted end
- ;
- }
- // dispatcher;
-
- mkHylixBindGroup = category: binds: {
- inherit
- # keep-sorted start
- binds
- category
- # keep-sorted end
- ;
- };
-
- mkHylixDispatcher = toLua: bind:
- if bind.exec != null
- then
- if bind.execRules != null
- then "hl.dsp.exec_cmd(${toLua bind.exec}, ${toLua bind.execRules})"
- else "hl.dsp.exec_cmd(${toLua bind.exec})"
- else if bind.execRaw != null
- then "hl.dsp.exec_raw(${toLua bind.execRaw})"
- else if bind.lua != null
- then bind.lua
- else if bind.action != null
- then let
- argsStr =
- if bind.args != null
- then "(${toLua bind.args})"
- else "()";
- in "hl.dsp.${bind.action}${argsStr}"
- else throw "bind must have one of: exec, action, lua";
-
- mkHylixBindLine = toLua: bind: let
- keysStr = concatStringsSep " + " bind.keys;
- dispatcher = mkHylixDispatcher toLua bind;
- bindOptions = cleanAttrs (bind.options // {inherit (bind) description;});
- in
- if bindOptions != {}
- then "hl.bind(${toLua keysStr}, ${dispatcher}, ${toLua bindOptions})"
- else "hl.bind(${toLua keysStr}, ${dispatcher})";
-
- mkHylixBindLines = toLua: binds: let
- buildBind = state: bind: let
- categoryChanged = bind.category != null && bind.category != state.category;
- nextIndex =
- if categoryChanged
- then state.index + 1
- else state.index;
- categoryLine =
- if categoryChanged
- then ["-- ${toString nextIndex}. ${bind.category}"]
- else [];
- in {
- category =
- if categoryChanged
- then bind.category
- else state.category;
- index = nextIndex;
- lines = state.lines ++ categoryLine ++ [(mkHylixBindLine toLua bind)];
- };
- in
- (foldl' buildBind {
- category = null;
- index = 0;
- lines = [];
- }
- binds)
- .lines;
-
- mkHylixGroupedBinds = bindGroups:
- concatMap (group:
- map (bind:
- bind
- // {
- category =
- if bind.category != null
- then bind.category
- else group.category;
- })
- group.binds)
- bindGroups;
-
- mkHylixMonitorLine = toLua: monitor: let
- scaleVal =
- if monitor.scale != null && isString monitor.scale
- then fromJSON monitor.scale
- else monitor.scale;
- base =
- {inherit (monitor) output;}
- // optionalAttrs (monitor.mode != null) {inherit (monitor) mode;}
- // optionalAttrs (monitor.position != null) {inherit (monitor) position;}
- // optionalAttrs (scaleVal != null) {scale = scaleVal;};
- in "hl.monitor(${toLua (base // monitor.extra)})";
-
- mkHylixRuleLine = toLua: func: rule: "${func}(${toLua rule})";
-
- mkHylixCurveLine = toLua: name: curve: let
- table =
- if curve.type == "bezier"
- then {
- type = "bezier";
- points = [
- [
- (builtins.elemAt curve.points 0)
- (builtins.elemAt curve.points 1)
- ]
- [
- (builtins.elemAt curve.points 2)
- (builtins.elemAt curve.points 3)
- ]
- ];
- }
- else
- cleanAttrs {
- inherit
- (curve)
- dampening
- mass
- stiffness
- type
- ;
- };
- in "hl.curve(\"${name}\", ${toLua table})";
-
- mkHylixAnimationLineWithCurves = toLua: curves: anim: let
- bezier = anim.bezier or null;
- speed = anim.speed or null;
- canScaleSpring = (anim.spring or null) != null && speed != null && speed > 0 && hasAttr anim.spring curves;
- spring =
- if canScaleSpring
- then mkDerivedSpringName anim
- else anim.spring or null;
- style = anim.style or null;
- table =
- {inherit (anim) leaf enabled;}
- // optionalAttrs (speed != null) {inherit speed;}
- // optionalAttrs (bezier != null) {inherit bezier;}
- // optionalAttrs (spring != null) {inherit spring;}
- // optionalAttrs (style != null) {inherit style;};
- in "hl.animation(${toLua table})";
-
- mkHylixAnimationLine = toLua: anim:
- mkHylixAnimationLineWithCurves toLua {} anim;
-
- mkHylixDerivedSpringLine = toLua: curves: anim:
- if
- (anim.spring or null)
- != null
- && (anim.speed or null) != null
- && anim.speed > 0
- && hasAttr anim.spring curves
- then let
- curve = curves.${anim.spring};
- in
- if curve.type == "spring"
- then mkHylixCurveLine toLua (mkDerivedSpringName anim) (scaleSpringForSpeed anim.speed curve)
- else null
- else null;
-
- mkHylixCurveLines = toLua: curves:
- concatStringsSep "\n" (mapAttrsToList (mkHylixCurveLine toLua) curves);
-
- mkHylixAnimationLinesWithCurves = toLua: curves: animations:
- concatStringsSep "\n" (filter (line: line != null) (
- (map (mkHylixDerivedSpringLine toLua curves) animations)
- ++ (map (mkHylixAnimationLineWithCurves toLua curves) animations)
- ));
-
- mkHylixAnimationLines = toLua: animations:
- mkHylixAnimationLinesWithCurves toLua {} animations;
-}
+ animations = import ./modules/animations.nix {inherit lib;};
+ binds = import ./modules/binds.nix {inherit lib;};
+ core = import ./modules/core.nix {inherit lib;};
+ hyprland = import ./modules/hyprland.nix {inherit lib;};
+in
+ removeAttrs core ["cleanAttrs"]
+ // binds
+ // hyprland
+ // animations
diff --git a/lib/modules/animations.nix b/lib/modules/animations.nix
new file mode 100644
index 0000000..d1da477
--- /dev/null
+++ b/lib/modules/animations.nix
@@ -0,0 +1,120 @@
+{lib}: let
+ inherit
+ (builtins)
+ # keep-sorted start
+ filter
+ hasAttr
+ # keep-sorted end
+ ;
+ inherit
+ (lib)
+ # keep-sorted start
+ concatStringsSep
+ mapAttrsToList
+ optionalAttrs
+ pipe
+ replaceStrings
+ # keep-sorted end
+ ;
+ inherit
+ (import ./core.nix {inherit lib;})
+ # keep-sorted start
+ cleanAttrs
+ mkHylixLuaValueCall
+ # keep-sorted end
+ ;
+
+ sanitizeCurveName = replaceStrings [":" "/" " " "-" "."] ["_" "_" "_" "_" "_"];
+
+ mkDerivedSpringName = anim: "hylix_${sanitizeCurveName anim.leaf}_${sanitizeCurveName anim.spring}";
+
+ canScaleSpring = curves: anim:
+ (anim.spring or null)
+ != null
+ && (anim.speed or null) != null
+ && anim.speed > 0
+ && hasAttr anim.spring curves;
+
+ scaleSpringForSpeed = speed: curve: let
+ timeScale = speed / 10.0;
+ in
+ curve
+ // optionalAttrs ((curve.stiffness or null) != null) {
+ stiffness = curve.stiffness / (timeScale * timeScale);
+ }
+ // optionalAttrs ((curve.dampening or null) != null) {
+ dampening = curve.dampening / timeScale;
+ };
+in rec {
+ mkHylixCurveLine = toLua: name: curve: let
+ table =
+ if curve.type == "bezier"
+ then {
+ type = "bezier";
+ points = [
+ [
+ (builtins.elemAt curve.points 0)
+ (builtins.elemAt curve.points 1)
+ ]
+ [
+ (builtins.elemAt curve.points 2)
+ (builtins.elemAt curve.points 3)
+ ]
+ ];
+ }
+ else
+ cleanAttrs {
+ inherit
+ (curve)
+ dampening
+ mass
+ stiffness
+ type
+ ;
+ };
+ in
+ mkHylixLuaValueCall toLua "hl.curve" [name table];
+
+ mkHylixAnimationLineWithCurves = toLua: curves: anim: let
+ bezier = anim.bezier or null;
+ speed = anim.speed or null;
+ spring =
+ if canScaleSpring curves anim
+ then mkDerivedSpringName anim
+ else anim.spring or null;
+ style = anim.style or null;
+ table = cleanAttrs {
+ inherit (anim) enabled leaf;
+ inherit bezier speed spring style;
+ };
+ in
+ mkHylixLuaValueCall toLua "hl.animation" [table];
+
+ mkHylixAnimationLine = toLua: anim:
+ mkHylixAnimationLineWithCurves toLua {} anim;
+
+ mkHylixDerivedSpringLine = toLua: curves: anim:
+ if canScaleSpring curves anim
+ then let
+ curve = curves.${anim.spring};
+ in
+ if curve.type == "spring"
+ then mkHylixCurveLine toLua (mkDerivedSpringName anim) (scaleSpringForSpeed anim.speed curve)
+ else null
+ else null;
+
+ mkHylixCurveLines = toLua: curves:
+ concatStringsSep "\n" (mapAttrsToList (mkHylixCurveLine toLua) curves);
+
+ mkHylixAnimationLinesWithCurves = toLua: curves: animations:
+ pipe animations [
+ (items:
+ (map (mkHylixDerivedSpringLine toLua curves) items)
+ ++ (map (mkHylixAnimationLineWithCurves toLua curves) items))
+ (filter (line: line != null))
+ (concatStringsSep "\n")
+ ];
+
+ mkHylixAnimationLines = toLua: animations:
+ mkHylixAnimationLinesWithCurves toLua {} animations;
+}
diff --git a/lib/modules/binds.nix b/lib/modules/binds.nix
new file mode 100644
index 0000000..fd43393
--- /dev/null
+++ b/lib/modules/binds.nix
@@ -0,0 +1,115 @@
+{lib}: let
+ inherit
+ (builtins)
+ # keep-sorted start
+ filter
+ head
+ # keep-sorted end
+ ;
+ inherit
+ (lib)
+ # keep-sorted start
+ concatMap
+ concatStringsSep
+ foldl'
+ optional
+ optionalAttrs
+ # keep-sorted end
+ ;
+ inherit
+ (import ./core.nix {inherit lib;})
+ # keep-sorted start
+ cleanAttrs
+ mkHylixLuaCall
+ mkHylixLuaValueCall
+ # keep-sorted end
+ ;
+in rec {
+ mkHylixBind = description: keys: dispatcher:
+ {
+ inherit
+ # keep-sorted start
+ description
+ keys
+ # keep-sorted end
+ ;
+ }
+ // dispatcher;
+
+ mkHylixBindGroup = category: binds: {
+ inherit
+ # keep-sorted start
+ binds
+ category
+ # keep-sorted end
+ ;
+ };
+
+ mkHylixDispatcher = toLua: bind: let
+ candidates = [
+ {
+ condition = bind.exec != null;
+ value = mkHylixLuaValueCall toLua "hl.dsp.exec_cmd" ([bind.exec] ++ optional (bind.execRules != null) bind.execRules);
+ }
+ {
+ condition = bind.execRaw != null;
+ value = mkHylixLuaValueCall toLua "hl.dsp.exec_raw" [bind.execRaw];
+ }
+ {
+ condition = bind.lua != null;
+ value = bind.lua;
+ }
+ {
+ condition = bind.action != null;
+ value = mkHylixLuaValueCall toLua "hl.dsp.${bind.action}" (optional (bind.args != null) bind.args);
+ }
+ ];
+ matches = filter (candidate: candidate.condition) candidates;
+ in
+ if matches != []
+ then (head matches).value
+ else throw "bind must have one of: exec, action, lua";
+
+ mkHylixBindLine = toLua: bind: let
+ keysStr = concatStringsSep " + " bind.keys;
+ dispatcher = mkHylixDispatcher toLua bind;
+ bindOptions = cleanAttrs (bind.options // {inherit (bind) description;});
+ in
+ mkHylixLuaCall "hl.bind" ([(toLua keysStr) dispatcher] ++ optional (bindOptions != {}) (toLua bindOptions));
+
+ mkHylixBindLines = toLua: binds: let
+ buildBind = state: bind: let
+ categoryChanged = bind.category != null && bind.category != state.category;
+ nextIndex =
+ if categoryChanged
+ then state.index + 1
+ else state.index;
+ categoryLine =
+ optional categoryChanged "-- ${toString nextIndex}. ${bind.category}";
+ in {
+ category =
+ if categoryChanged
+ then bind.category
+ else state.category;
+ index = nextIndex;
+ lines = state.lines ++ categoryLine ++ [(mkHylixBindLine toLua bind)];
+ };
+ in
+ (foldl' buildBind {
+ category = null;
+ index = 0;
+ lines = [];
+ }
+ binds)
+ .lines;
+
+ mkHylixGroupedBinds = bindGroups:
+ concatMap (group:
+ map (bind:
+ bind
+ // optionalAttrs (bind.category == null) {
+ inherit (group) category;
+ })
+ group.binds)
+ bindGroups;
+}
diff --git a/lib/modules/core.nix b/lib/modules/core.nix
new file mode 100644
index 0000000..0eb9958
--- /dev/null
+++ b/lib/modules/core.nix
@@ -0,0 +1,28 @@
+{lib}: let
+ inherit
+ (lib)
+ # keep-sorted start
+ concatStringsSep
+ filterAttrs
+ mkIf
+ mkOrder
+ # keep-sorted end
+ ;
+in rec {
+ cleanAttrs = filterAttrs (_: value: value != null);
+
+ mkHylixGeneratedConfig = condition: order: text:
+ mkIf condition {
+ programs.hylix._generatedConfig = mkOrder order text;
+ };
+
+ mkHylixLines = lineFn: values:
+ concatStringsSep "\n" (map lineFn values);
+
+ mkHylixLuaCall = name: args: "${name}(${concatStringsSep ", " args})";
+
+ mkHylixLuaValueCall = toLua: name: args: mkHylixLuaCall name (map toLua args);
+
+ mkHylixLuaCallLines = toLua: func: values:
+ mkHylixLines (value: mkHylixLuaValueCall toLua func [value]) values;
+}
diff --git a/lib/modules/hyprland.nix b/lib/modules/hyprland.nix
new file mode 100644
index 0000000..90aed0e
--- /dev/null
+++ b/lib/modules/hyprland.nix
@@ -0,0 +1,67 @@
+{lib}: let
+ inherit
+ (builtins)
+ # keep-sorted start
+ filter
+ fromJSON
+ head
+ isString
+ # keep-sorted end
+ ;
+ inherit
+ (lib)
+ # keep-sorted start
+ concatStringsSep
+ mapAttrsToList
+ optional
+ # keep-sorted end
+ ;
+ inherit
+ (import ./core.nix {inherit lib;})
+ # keep-sorted start
+ cleanAttrs
+ mkHylixLuaCall
+ mkHylixLuaValueCall
+ # keep-sorted end
+ ;
+in rec {
+ mkHylixMonitorLine = toLua: monitor: let
+ scaleVal =
+ if monitor.scale != null && isString monitor.scale
+ then fromJSON monitor.scale
+ else monitor.scale;
+ base = cleanAttrs {
+ inherit (monitor) mode output position;
+ scale = scaleVal;
+ };
+ in
+ mkHylixLuaValueCall toLua "hl.monitor" [(base // monitor.extra)];
+
+ mkHylixRuleLine = toLua: func: rule: mkHylixLuaValueCall toLua func [rule];
+
+ mkHylixAutostartLine = toLua: entry:
+ mkHylixLuaValueCall toLua "hl.exec_cmd" ([entry.cmd] ++ optional (entry.rules != null) entry.rules);
+
+ mkHylixEnvLine = toLua: name: value:
+ mkHylixLuaValueCall toLua "hl.env" [name value];
+
+ mkHylixEnvLines = toLua: env:
+ concatStringsSep "\n" (mapAttrsToList (mkHylixEnvLine toLua) env);
+
+ mkHylixEventLine = toLua: entry: let
+ callbacks = [
+ {
+ condition = entry.lua != null;
+ value = entry.lua;
+ }
+ {
+ condition = entry.exec != null;
+ value = "function() ${mkHylixLuaValueCall toLua "hl.dsp.exec_cmd" [entry.exec]} end";
+ }
+ ];
+ matches = filter (candidate: candidate.condition) callbacks;
+ in
+ if matches != []
+ then mkHylixLuaCall "hl.on" [(toLua entry.event) (head matches).value]
+ else "";
+}
diff --git a/lib/toLua.nix b/lib/toLua.nix
index e8b74c3..63c05da 100644
--- a/lib/toLua.nix
+++ b/lib/toLua.nix
@@ -8,13 +8,6 @@
genList
hasAttr
head
- isAttrs
- isBool
- isFloat
- isInt
- isList
- isPath
- isString
length
tail
typeOf
@@ -99,27 +92,25 @@
indent = depth:
concatStringsSep "" (genList (_: " ") depth);
- toLuaValue = depth: value:
- if value == null
- then "nil"
- else if isBool value
- then boolToString value
- else if isInt value
- then toString value
- else if isFloat value
- then stripTrailingZeros (toString value)
- else if isString value
- then "\"${escapeLuaString value}\""
- else if isPath value
- then "\"${escapeLuaString (toString value)}\""
- else if isList value
- then toLuaList depth value
- else if isAttrs value
- then
- if hasAttr "__raw" value
- then value.__raw
- else toLuaTable depth value
- else throw "toLua: unsupported type ${typeOf value}";
+ toLuaValue = depth: value: let
+ renderers = {
+ bool = boolToString;
+ float = value: stripTrailingZeros (toString value);
+ int = toString;
+ list = toLuaList depth;
+ null = _: "nil";
+ path = value: "\"${escapeLuaString (toString value)}\"";
+ set = value:
+ if hasAttr "__raw" value
+ then value.__raw
+ else toLuaTable depth value;
+ string = value: "\"${escapeLuaString value}\"";
+ };
+ valueType = typeOf value;
+ in
+ if hasAttr valueType renderers
+ then renderers.${valueType} value
+ else throw "toLua: unsupported type ${valueType}";
toLuaList = depth: xs: let
inner = indent (depth + 1);
diff --git a/modules/hylix/animations.nix b/modules/hylix/animations.nix
index 32a462a..fa024b8 100644
--- a/modules/hylix/animations.nix
+++ b/modules/hylix/animations.nix
@@ -9,10 +9,8 @@ _: {
inherit
(lib)
# keep-sorted start
- mkIf
mkMerge
mkOption
- mkOrder
# keep-sorted end
;
inherit
@@ -20,6 +18,7 @@ _: {
# keep-sorted start
mkHylixAnimationLinesWithCurves
mkHylixCurveLines
+ mkHylixGeneratedConfig
ordering
toLua
# keep-sorted end
@@ -153,13 +152,9 @@ _: {
};
config = mkMerge [
- (mkIf (cfg.animations.curves != {}) {
- programs.hylix._generatedConfig = mkOrder ordering.curves curveLines;
- })
+ (mkHylixGeneratedConfig (cfg.animations.curves != {}) ordering.curves curveLines)
- (mkIf (cfg.animations.animations != []) {
- programs.hylix._generatedConfig = mkOrder ordering.animations animLines;
- })
+ (mkHylixGeneratedConfig (cfg.animations.animations != []) ordering.animations animLines)
];
};
}
diff --git a/modules/hylix/autostart.nix b/modules/hylix/autostart.nix
index 111fd2a..83b2d96 100644
--- a/modules/hylix/autostart.nix
+++ b/modules/hylix/autostart.nix
@@ -9,15 +9,15 @@ _: {
inherit
(lib)
# keep-sorted start
- concatStringsSep
- mkIf
mkOption
- mkOrder
# keep-sorted end
;
inherit
(import ../../lib {inherit lib;})
# keep-sorted start
+ mkHylixAutostartLine
+ mkHylixGeneratedConfig
+ mkHylixLines
ordering
toLua
# keep-sorted end
@@ -35,15 +35,7 @@ _: {
cfg = config.programs.hylix;
- lines =
- concatStringsSep "\n"
- (map (
- entry:
- if entry.rules != null
- then "hl.exec_cmd(${toLua entry.cmd}, ${toLua entry.rules})"
- else "hl.exec_cmd(${toLua entry.cmd})"
- )
- cfg.autostart);
+ lines = mkHylixLines (mkHylixAutostartLine toLua) cfg.autostart;
in {
options.programs.hylix.autostart = mkOption {
description = "commands to run at startup via hl.exec_cmd()";
@@ -69,8 +61,6 @@ _: {
default = [];
};
- config = mkIf (cfg.autostart != []) {
- programs.hylix._generatedConfig = mkOrder ordering.autostart lines;
- };
+ config = mkHylixGeneratedConfig (cfg.autostart != []) ordering.autostart lines;
};
}
diff --git a/modules/hylix/binds.nix b/modules/hylix/binds.nix
index e12744b..f6d3f6d 100644
--- a/modules/hylix/binds.nix
+++ b/modules/hylix/binds.nix
@@ -10,15 +10,14 @@
(lib)
# keep-sorted start
concatStringsSep
- mkIf
mkOption
- mkOrder
# keep-sorted end
;
inherit
(import ../../lib {inherit lib;})
# keep-sorted start
mkHylixBindLines
+ mkHylixGeneratedConfig
mkHylixGroupedBinds
ordering
toLua
@@ -150,8 +149,6 @@
default = [];
};
- config = mkIf (allBinds != []) {
- programs.hylix._generatedConfig = mkOrder ordering.binds (concatStringsSep "\n" lines);
- };
+ config = mkHylixGeneratedConfig (allBinds != []) ordering.binds (concatStringsSep "\n" lines);
};
}
diff --git a/modules/hylix/devices.nix b/modules/hylix/devices.nix
index d5dbdff..c0bdf82 100644
--- a/modules/hylix/devices.nix
+++ b/modules/hylix/devices.nix
@@ -9,15 +9,14 @@ _: {
inherit
(lib)
# keep-sorted start
- concatStringsSep
- mkIf
mkOption
- mkOrder
# keep-sorted end
;
inherit
(import ../../lib {inherit lib;})
# keep-sorted start
+ mkHylixGeneratedConfig
+ mkHylixLuaCallLines
ordering
toLua
# keep-sorted end
@@ -32,9 +31,7 @@ _: {
cfg = config.programs.hylix;
- lines =
- concatStringsSep "\n"
- (map (d: "hl.device(${toLua d})") cfg.devices);
+ lines = mkHylixLuaCallLines toLua "hl.device" cfg.devices;
in {
options.programs.hylix.devices = mkOption {
description = "device configurations passed to hl.device()";
@@ -43,8 +40,6 @@ _: {
default = [];
};
- config = mkIf (cfg.devices != []) {
- programs.hylix._generatedConfig = mkOrder ordering.devices lines;
- };
+ config = mkHylixGeneratedConfig (cfg.devices != []) ordering.devices lines;
};
}
diff --git a/modules/hylix/env.nix b/modules/hylix/env.nix
index 8923c9b..45ff172 100644
--- a/modules/hylix/env.nix
+++ b/modules/hylix/env.nix
@@ -9,14 +9,18 @@ _: {
inherit
(lib)
# keep-sorted start
- concatStringsSep
- mapAttrsToList
- mkIf
mkOption
- mkOrder
# keep-sorted end
;
- inherit (import ../../lib {inherit lib;}) ordering;
+ inherit
+ (import ../../lib {inherit lib;})
+ # keep-sorted start
+ mkHylixEnvLines
+ mkHylixGeneratedConfig
+ ordering
+ toLua
+ # keep-sorted end
+ ;
inherit
(lib.types)
# keep-sorted start
@@ -26,9 +30,7 @@ _: {
;
cfg = config.programs.hylix;
- envLines =
- concatStringsSep "\n"
- (mapAttrsToList (k: v: "hl.env(\"${k}\", \"${v}\")") cfg.env);
+ envLines = mkHylixEnvLines toLua cfg.env;
in {
options.programs.hylix.env = mkOption {
description = "environment variables set via hl.env()";
@@ -37,8 +39,6 @@ _: {
default = {};
};
- config = mkIf (cfg.env != {}) {
- programs.hylix._generatedConfig = mkOrder ordering.env envLines;
- };
+ config = mkHylixGeneratedConfig (cfg.env != {}) ordering.env envLines;
};
}
diff --git a/modules/hylix/events.nix b/modules/hylix/events.nix
index 3336c2a..99bce7c 100644
--- a/modules/hylix/events.nix
+++ b/modules/hylix/events.nix
@@ -9,15 +9,15 @@ _: {
inherit
(lib)
# keep-sorted start
- concatStringsSep
- mkIf
mkOption
- mkOrder
# keep-sorted end
;
inherit
(import ../../lib {inherit lib;})
# keep-sorted start
+ mkHylixEventLine
+ mkHylixGeneratedConfig
+ mkHylixLines
ordering
toLua
# keep-sorted end
@@ -34,17 +34,7 @@ _: {
cfg = config.programs.hylix;
- lines =
- concatStringsSep "\n"
- (map (
- entry:
- if entry.lua != null
- then "hl.on(${toLua entry.event}, ${entry.lua})"
- else if entry.exec != null
- then "hl.on(${toLua entry.event}, function() hl.dsp.exec_cmd(${toLua entry.exec}) end)"
- else ""
- )
- cfg.events);
+ lines = mkHylixLines (mkHylixEventLine toLua) cfg.events;
in {
options.programs.hylix.events = mkOption {
description = "Hyprland event hooks via hl.on()";
@@ -75,8 +65,6 @@ _: {
default = [];
};
- config = mkIf (cfg.events != []) {
- programs.hylix._generatedConfig = mkOrder ordering.events lines;
- };
+ config = mkHylixGeneratedConfig (cfg.events != []) ordering.events lines;
};
}
diff --git a/modules/hylix/extraLua.nix b/modules/hylix/extraLua.nix
index 89a64c8..7016082 100644
--- a/modules/hylix/extraLua.nix
+++ b/modules/hylix/extraLua.nix
@@ -11,11 +11,17 @@ _: {
# keep-sorted start
concatStringsSep
mkIf
+ mkMerge
mkOption
- mkOrder
# keep-sorted end
;
- inherit (import ../../lib {inherit lib;}) ordering;
+ inherit
+ (import ../../lib {inherit lib;})
+ # keep-sorted start
+ mkHylixGeneratedConfig
+ ordering
+ # keep-sorted end
+ ;
inherit
(lib.types)
# keep-sorted start
@@ -40,11 +46,14 @@ _: {
default = [];
};
- config = {
- programs.hylix = {
- extraLua = mkIf (cfg.extraLuaSnippets != []) (concatStringsSep "\n" cfg.extraLuaSnippets);
- _generatedConfig = mkIf (cfg.extraLua != "") (mkOrder ordering.extraLua cfg.extraLua);
- };
- };
+ config = mkMerge [
+ {
+ programs.hylix = {
+ extraLua = mkIf (cfg.extraLuaSnippets != []) (concatStringsSep "\n" cfg.extraLuaSnippets);
+ };
+ }
+
+ (mkHylixGeneratedConfig (cfg.extraLua != "") ordering.extraLua cfg.extraLua)
+ ];
};
}
diff --git a/modules/hylix/gestures.nix b/modules/hylix/gestures.nix
index 2507ff7..1dd98f3 100644
--- a/modules/hylix/gestures.nix
+++ b/modules/hylix/gestures.nix
@@ -9,13 +9,18 @@ _: {
inherit
(lib)
# keep-sorted start
- concatStringsSep
- mkIf
mkOption
- mkOrder
# keep-sorted end
;
- inherit (import ../../lib {inherit lib;}) toLua ordering;
+ inherit
+ (import ../../lib {inherit lib;})
+ # keep-sorted start
+ mkHylixGeneratedConfig
+ mkHylixLuaCallLines
+ ordering
+ toLua
+ # keep-sorted end
+ ;
inherit
(lib.types)
# keep-sorted start
@@ -26,9 +31,7 @@ _: {
cfg = config.programs.hylix;
- lines =
- concatStringsSep "\n"
- (map (g: "hl.gesture(${toLua g})") cfg.gestures);
+ lines = mkHylixLuaCallLines toLua "hl.gesture" cfg.gestures;
in {
options.programs.hylix.gestures = mkOption {
description = "gesture configurations passed to hl.gesture()";
@@ -37,8 +40,6 @@ _: {
default = [];
};
- config = mkIf (cfg.gestures != []) {
- programs.hylix._generatedConfig = mkOrder ordering.gestures lines;
- };
+ config = mkHylixGeneratedConfig (cfg.gestures != []) ordering.gestures lines;
};
}
diff --git a/modules/hylix/monitors.nix b/modules/hylix/monitors.nix
index 6661294..f875eb1 100644
--- a/modules/hylix/monitors.nix
+++ b/modules/hylix/monitors.nix
@@ -9,15 +9,14 @@ _: {
inherit
(lib)
# keep-sorted start
- concatStringsSep
- mkIf
mkOption
- mkOrder
# keep-sorted end
;
inherit
(import ../../lib {inherit lib;})
# keep-sorted start
+ mkHylixGeneratedConfig
+ mkHylixLines
mkHylixMonitorLine
ordering
toLua
@@ -39,7 +38,7 @@ _: {
cfg = config.programs.hylix;
- lines = concatStringsSep "\n" (map (mkHylixMonitorLine toLua) cfg.monitors);
+ lines = mkHylixLines (mkHylixMonitorLine toLua) cfg.monitors;
monitorType = submodule {
options = {
@@ -88,8 +87,6 @@ _: {
default = [];
};
- config = mkIf (cfg.monitors != []) {
- programs.hylix._generatedConfig = mkOrder ordering.monitors lines;
- };
+ config = mkHylixGeneratedConfig (cfg.monitors != []) ordering.monitors lines;
};
}
diff --git a/modules/hylix/notifications.nix b/modules/hylix/notifications.nix
index 88860e8..bad3e07 100644
--- a/modules/hylix/notifications.nix
+++ b/modules/hylix/notifications.nix
@@ -9,15 +9,14 @@ _: {
inherit
(lib)
# keep-sorted start
- concatStringsSep
- mkIf
mkOption
- mkOrder
# keep-sorted end
;
inherit
(import ../../lib {inherit lib;})
# keep-sorted start
+ mkHylixGeneratedConfig
+ mkHylixLuaCallLines
ordering
toLua
# keep-sorted end
@@ -35,9 +34,7 @@ _: {
cfg = config.programs.hylix;
- lines =
- concatStringsSep "\n"
- (map (n: "hl.notification.create(${toLua n})") cfg.notifications);
+ lines = mkHylixLuaCallLines toLua "hl.notification.create" cfg.notifications;
in {
options.programs.hylix.notifications = mkOption {
description = "notifications sent on startup via hl.notification.create()";
@@ -75,8 +72,6 @@ _: {
default = [];
};
- config = mkIf (cfg.notifications != []) {
- programs.hylix._generatedConfig = mkOrder ordering.notifications lines;
- };
+ config = mkHylixGeneratedConfig (cfg.notifications != []) ordering.notifications lines;
};
}
diff --git a/modules/hylix/permissions.nix b/modules/hylix/permissions.nix
index 596071a..063f0c6 100644
--- a/modules/hylix/permissions.nix
+++ b/modules/hylix/permissions.nix
@@ -9,13 +9,19 @@ _: {
inherit
(lib)
# keep-sorted start
- concatStringsSep
- mkIf
mkOption
- mkOrder
# keep-sorted end
;
- inherit (import ../../lib {inherit lib;}) toLua ordering;
+ inherit
+ (import ../../lib {inherit lib;})
+ # keep-sorted start
+ mkHylixGeneratedConfig
+ mkHylixLines
+ mkHylixLuaValueCall
+ ordering
+ toLua
+ # keep-sorted end
+ ;
inherit
(lib.types)
# keep-sorted start
@@ -51,9 +57,7 @@ _: {
};
};
- lines =
- concatStringsSep "\n"
- (map (p: "hl.permission(${toLua {inherit (p) binary mode type;}})") cfg.permissions);
+ lines = mkHylixLines (p: mkHylixLuaValueCall toLua "hl.permission" [{inherit (p) binary mode type;}]) cfg.permissions;
in {
options.programs.hylix.permissions = mkOption {
description = "permission rules";
@@ -62,8 +66,6 @@ _: {
default = [];
};
- config = mkIf (cfg.permissions != []) {
- programs.hylix._generatedConfig = mkOrder ordering.permissions lines;
- };
+ config = mkHylixGeneratedConfig (cfg.permissions != []) ordering.permissions lines;
};
}
diff --git a/modules/hylix/rules.nix b/modules/hylix/rules.nix
index 9f23178..2a259b1 100644
--- a/modules/hylix/rules.nix
+++ b/modules/hylix/rules.nix
@@ -9,16 +9,15 @@ _: {
inherit
(lib)
# keep-sorted start
- concatStringsSep
- mkIf
mkMerge
mkOption
- mkOrder
# keep-sorted end
;
inherit
(import ../../lib {inherit lib;})
# keep-sorted start
+ mkHylixGeneratedConfig
+ mkHylixLines
mkHylixRuleLine
ordering
toLua
@@ -34,6 +33,29 @@ _: {
cfg = config.programs.hylix;
buildRule = mkHylixRuleLine toLua;
+ ruleSections = [
+ {
+ func = "hl.window_rule";
+ order = ordering.windowRules;
+ values = cfg.rules.window;
+ }
+ {
+ func = "hl.workspace_rule";
+ order = ordering.workspaceRules;
+ values = cfg.rules.workspace;
+ }
+ {
+ func = "hl.layer_rule";
+ order = ordering.layerRules;
+ values = cfg.rules.layer;
+ }
+ ];
+ mkRuleSection = {
+ func,
+ order,
+ values,
+ }:
+ mkHylixGeneratedConfig (values != []) order (mkHylixLines (buildRule func) values);
in {
options.programs.hylix.rules = {
# keep-sorted start block=yes newline_separated=yes
@@ -60,24 +82,6 @@ _: {
# keep-sorted end
};
- config = mkMerge [
- (mkIf (cfg.rules.window != []) {
- programs.hylix._generatedConfig =
- mkOrder ordering.windowRules
- (concatStringsSep "\n" (map (buildRule "hl.window_rule") cfg.rules.window));
- })
-
- (mkIf (cfg.rules.workspace != []) {
- programs.hylix._generatedConfig =
- mkOrder ordering.workspaceRules
- (concatStringsSep "\n" (map (buildRule "hl.workspace_rule") cfg.rules.workspace));
- })
-
- (mkIf (cfg.rules.layer != []) {
- programs.hylix._generatedConfig =
- mkOrder ordering.layerRules
- (concatStringsSep "\n" (map (buildRule "hl.layer_rule") cfg.rules.layer));
- })
- ];
+ config = mkMerge (map mkRuleSection ruleSections);
};
}
diff --git a/modules/hylix/settings.nix b/modules/hylix/settings.nix
index e494fb2..26a2f5c 100644
--- a/modules/hylix/settings.nix
+++ b/modules/hylix/settings.nix
@@ -9,17 +9,17 @@ _: {
inherit
(lib)
# keep-sorted start
- mkIf
mkOption
- mkOrder
# keep-sorted end
;
inherit
(import ../../lib {inherit lib;})
# keep-sorted start
+ mkHylixGeneratedConfig
+ mkHylixLuaValueCall
ordering
toLua
- #keep-sorted end
+ # keep-sorted end
;
inherit (lib.types) anything;
cfg = config.programs.hylix;
@@ -31,10 +31,10 @@ _: {
default = {};
};
- config = mkIf (cfg.settings != {}) {
- programs.hylix._generatedConfig =
- mkOrder ordering.settings
- "hl.config(${toLua cfg.settings})";
- };
+ config =
+ mkHylixGeneratedConfig
+ (cfg.settings != {})
+ ordering.settings
+ (mkHylixLuaValueCall toLua "hl.config" [cfg.settings]);
};
}
diff --git a/modules/treefmt.nix b/modules/treefmt.nix
index 6d95d50..b5410c4 100644
--- a/modules/treefmt.nix
+++ b/modules/treefmt.nix
@@ -19,6 +19,7 @@
settings.global.excludes = [
# keep-sorted start
".direnv/*"
+ ".envrc"
"flake.nix"
# keep-sorted end
];