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 @@
- Nix logo + Nix logo # hylix Hyprland configuration framework. + [![Repo Size](https://img.shields.io/github/repo-size/adam01110/hylix?style=flat-square&label=repo%20size&labelColor=504945&color=3c3836)](https://github.com/adam01110/hylix) +
[![Nix](https://img.shields.io/badge/Nix-flakes-689d6a?style=flat-square&labelColor=504945&logo=nixos&logoColor=ebdbb2)](https://nixos.wiki/wiki/Flakes) [![Hyprland](https://img.shields.io/badge/Hyprland-Lua%20config-458588?style=flat-square&labelColor=504945&color=458588)](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 ];