From c5915e1d245288a5e48cdd90ace934aa8856eb7f Mon Sep 17 00:00:00 2001 From: fau Date: Sun, 27 Jul 2025 18:06:22 +0200 Subject: [PATCH] niri: move config to nix Signed-off-by: faukah Change-Id: I6a6a6964cffaba7ce75488a48739398758d49363 --- modules/wms/niri/config.kdl | 433 ---------------------------------- modules/wms/niri/config.nix | 324 +++++++++++++++++++++++++ modules/wms/niri/kdl.nix | 323 +++++++++++++++++++++++++ modules/wms/niri/niri.mod.nix | 44 +++- 4 files changed, 690 insertions(+), 434 deletions(-) delete mode 100644 modules/wms/niri/config.kdl create mode 100644 modules/wms/niri/config.nix create mode 100644 modules/wms/niri/kdl.nix diff --git a/modules/wms/niri/config.kdl b/modules/wms/niri/config.kdl deleted file mode 100644 index bec4a4a..0000000 --- a/modules/wms/niri/config.kdl +++ /dev/null @@ -1,433 +0,0 @@ -input { - keyboard { - xkb { - layout "us,ru" - variant ",phonetic_winkeys" - options "grp:rctrl_rshift_toggle, compose:102" - } - repeat-rate 60 - repeat-delay 200 - numlock - } - touchpad { - tap - } - // focus-follows-mouse - focus-follows-mouse max-scroll-amount="0%" -} -// Laptop -output "eDP-1" { - mode "1920x1080@59.999" - scale 1 - position x=0 y=0 -} -// PC -output "DP-2" { - mode "1920x1080@59.999" - scale 1 - position x=0 y=0 -} -output "HDMI-A-1" { - mode "1920x1080@59.999" - scale 1 - position x=1920 y=0 -} -layout { - gaps 0 - center-focused-column "on-overflow" - focus-ring { - width 2 - active-color "#f9e2af" - inactive-color "transparent" - active-gradient from="#E5989B" to="#FFB4A2" angle=45 relative-to="workspace-view" in="oklch longer hue" - } - border { - off - } - tab-indicator { - width 2 - gap 4 - gaps-between-tabs 2 - } - shadow { - on - } - insert-hint { - color "#ffc87f80" - gradient from="#f38ba880" to="#f9e2af80" angle=45 relative-to="workspace-view" - } - preset-column-widths { - proportion 0.33333 - proportion 0.5 - proportion 0.66667 - } - default-column-width { - proportion 0.5 - } - background-color "transparent" -} -spawn-at-startup "waybar" -spawn-at-startup "nu" "-c" "quickshell --path ~/repos/projects/nichts/main/modules/style/quickshell/shell" -environment { - DISPLAY ":0" -} -layer-rule { - match namespace="overview$" - place-within-backdrop true -} -// prefer no client side decorations -prefer-no-csd -switch-events { - lid-close { - spawn "swaylock" - } -} -overview { - zoom 0.6 - backdrop-color "#777777" -} -animations { - window-close { - duration-ms 250 - curve "linear" - custom-shader "\n vec4 fall_and_rotate(vec3 coords_geo, vec3 size_geo) {\n\n float progress = niri_clamped_progress * niri_clamped_progress;\n vec2 coords = (coords_geo.xy - vec2(0.5, 1.0)) * size_geo.xy;\n coords.y -= progress * 1440.0;\n float random = (niri_random_seed - 0.5) / 2.0;\n random = sign(random) - random;\n float max_angle = 0.5 * random;\n float angle = progress * max_angle;\n mat2 rotate = mat2(cos(angle), -sin(angle), sin(angle), cos(angle));\n coords = rotate * coords;\n coords_geo = vec3(coords / size_geo.xy + vec2(0.5, 1.0), 1.0);\n vec3 coords_tex = niri_geo_to_tex * coords_geo;\n vec4 color = texture2D(niri_tex, coords_tex.st);\n\n return color;\n }\n\n vec4 close_color(vec3 coords_geo, vec3 size_geo) {\n return fall_and_rotate(coords_geo, size_geo);\n }\n " - } -} -window-rule { - match app-id="unset" - open-floating true -} -window-rule { - match app-id="org.gnome.Nautilus" - open-floating true -} -window-rule { - match app-id="org.freedesktop.impl.portal.desktop.kde" - open-floating true -} -window-rule { - draw-border-with-background false -} -// Fix discord screencasting -debug { - wait-for-frame-completion-in-pipewire -} -hotkey-overlay { - skip-at-startup -} -cursor { - xcursor-theme "BreezeX-RosePine-Linux" - xcursor-size 32 - hide-when-typing -} -binds { - Mod+Shift+Slash { - show-hotkey-overlay - } - Mod+Return { - spawn "ghostty" - } - Mod+Shift+Return { - spawn "sh" "-c" "niri msg action spawn -- ghostty; sleep 0.3; niri msg action consume-or-expel-window-left" - } - Mod+B { - spawn "brave" - } - // Mod+D { - // spawn "nu" "-c" "quickshell --path ~/repos/projects/nichts/main/modules/style/quickshell/shell msg launcher open" - // } - Mod+D { - spawn "fuzzel" - } - Mod+Alt+L { - spawn "swaylock" - } - // Audio - XF86AudioRaiseVolume allow-when-locked=true { - spawn "volumectl" "-u" "up" - } - XF86AudioLowerVolume allow-when-locked=true { - spawn "volumectl" "-u" "down" - } - XF86AudioMute allow-when-locked=true { - spawn "volumectl" "toggle-mute" - } - XF86AudioMicMute allow-when-locked=true { - spawn "volumectl" "-m" "toggle-mute" - } - XF86AudioPlay allow-when-locked=true { - spawn "playerctl" "play-pause" - } - XF86AudioNext allow-when-locked=true { - spawn "playerctl" "next" - } - XF86AudioPrev allow-when-locked=true { - spawn "playerctl" "previous" - } - // Monitor brightness - XF86MonBrightnessUp allow-when-locked=true { - spawn "lightctl" "up" - } - XF86MonBrightnessDown allow-when-locked=true { - spawn "lightctl" "down" - } - Mod+Q { - close-window - } - Mod+H { - focus-column-or-monitor-left - } - Mod+J { - focus-window-or-workspace-down - } - Mod+K { - focus-window-or-workspace-up - } - Mod+L { - focus-column-or-monitor-right - } - Mod+Shift+H { - move-column-left-or-to-monitor-left - } - Mod+Shift+J { - move-window-down-or-to-workspace-down - } - Mod+Shift+K { - move-window-up-or-to-workspace-up - } - Mod+Shift+L { - move-column-right-or-to-monitor-right - } - Mod+Home { - focus-column-first - } - Mod+End { - focus-column-last - } - Mod+Ctrl+Home { - move-column-to-first - } - Mod+Ctrl+End { - move-column-to-last - } - Mod+Ctrl+H { - focus-monitor-left - } - Mod+Ctrl+J { - focus-monitor-down - } - Mod+Ctrl+K { - focus-monitor-up - } - Mod+Ctrl+L { - focus-monitor-right - } - Mod+Shift+Ctrl+Left { - move-column-to-monitor-left - } - Mod+Shift+Ctrl+Down { - move-column-to-monitor-down - } - Mod+Shift+Ctrl+Up { - move-column-to-monitor-up - } - Mod+Shift+Ctrl+Right { - move-column-to-monitor-right - } - Mod+Shift+Ctrl+H { - move-column-to-monitor-left - } - Mod+Shift+Ctrl+J { - move-column-to-monitor-down - } - Mod+Shift+Ctrl+K { - move-column-to-monitor-up - } - Mod+Shift+Ctrl+L { - move-column-to-monitor-right - } - Mod+Page_Down { - focus-workspace-down - } - Mod+Page_Up { - focus-workspace-up - } - Mod+Shift+Page_Down { - move-column-to-workspace-down - } - Mod+Shift+Page_Up { - move-column-to-workspace-up - } - Mod+U { - focus-workspace-down - } - Mod+I { - focus-workspace-up - } - Mod+Shift+U { - move-column-to-workspace-down - } - Mod+Shift+I { - move-column-to-workspace-up - } - Mod+WheelScrollDown cooldown-ms=150 { - focus-workspace-down - } - Mod+WheelScrollUp cooldown-ms=150 { - focus-workspace-up - } - Mod+Shift+WheelScrollDown cooldown-ms=150 { - move-column-to-workspace-down - } - Mod+Shift+WheelScrollUp cooldown-ms=150 { - move-column-to-workspace-up - } - Mod+WheelScrollRight { - focus-column-right - } - Mod+WheelScrollLeft { - focus-column-left - } - Mod+Shift+WheelScrollRight { - move-column-right - } - Mod+Shift+WheelScrollLeft { - move-column-left - } - Mod+1 { - focus-workspace 1 - } - Mod+2 { - focus-workspace 2 - } - Mod+3 { - focus-workspace 3 - } - Mod+4 { - focus-workspace 4 - } - Mod+5 { - focus-workspace 5 - } - Mod+6 { - focus-workspace 6 - } - Mod+7 { - focus-workspace 7 - } - Mod+8 { - focus-workspace 8 - } - Mod+9 { - focus-workspace 9 - } - Mod+Shift+1 { - move-column-to-workspace 1 - } - Mod+Shift+2 { - move-column-to-workspace 2 - } - Mod+Shift+3 { - move-column-to-workspace 3 - } - Mod+Shift+4 { - move-column-to-workspace 4 - } - Mod+Shift+5 { - move-column-to-workspace 5 - } - Mod+Shift+6 { - move-column-to-workspace 6 - } - Mod+Shift+7 { - move-column-to-workspace 7 - } - Mod+Shift+8 { - move-column-to-workspace 8 - } - Mod+Shift+9 { - move-column-to-workspace 9 - } - Mod+BracketLeft { - consume-or-expel-window-left - } - Mod+BracketRight { - consume-or-expel-window-right - } - Mod+Comma { - consume-window-into-column - } - Mod+Period { - expel-window-from-column - } - Mod+R { - switch-preset-column-width - } - Mod+Shift+R { - switch-preset-window-height - } - Mod+Ctrl+R { - reset-window-height - } - Mod+F { - maximize-column - } - Mod+Shift+F { - fullscreen-window - } - Mod+Ctrl+F { - expand-column-to-available-width - } - Mod+C { - center-column - } - Mod+Minus { - set-column-width "-10%" - } - Mod+Equal { - set-column-width "+10%" - } - // Finer height adjustments when in column with other windows. - Mod+Shift+Minus { - set-window-height "-10%" - } - Mod+Shift+Equal { - set-window-height "+10%" - } - // Move the focused window between the floating and the tiling layout. - Mod+V { - toggle-window-floating - } - Mod+Shift+V { - switch-focus-between-floating-and-tiling - } - Mod+W { - toggle-column-tabbed-display - } - Mod+O { - toggle-overview - } - Print { - screenshot - } - Ctrl+Print { - screenshot-screen - } - // Alt+Print { - // spawn "sh" "-c" "" - // } - Mod+T { - screenshot - } - // "$mainMod, T, exec, ${getExe pkgs.grimblast} save area - | ${getExe pkgs.tesseract} - - | ${getExe' pkgs.wl-clipboard "wl-copy"}" - Mod+Escape allow-inhibiting=false { - toggle-keyboard-shortcuts-inhibit - } - Mod+Shift+E { - quit - } - Mod+Shift+P { - power-off-monitors - } -} - diff --git a/modules/wms/niri/config.nix b/modules/wms/niri/config.nix new file mode 100644 index 0000000..d799b74 --- /dev/null +++ b/modules/wms/niri/config.nix @@ -0,0 +1,324 @@ +{ + lib, + pkgs, + node, + plain, + leaf, + flag, +}: +let + inherit (lib.meta) getExe; + inherit (builtins) readFile; +in +[ + (plain "input" [ + (plain "keyboard" [ + (plain "xkb" [ + (leaf "layout" "us,ru") + (leaf "variant" ",phonetic_winkeys") + (leaf "options" "grp:rctrl_rshift_toggle, compose:102") + ]) + (leaf "repeat-rate" 60) + (leaf "repeat-delay" 200) + (flag "numlock") + ]) + (plain "touchpad" [ (flag "tap") ]) + (leaf "focus-follows-mouse" { max-scroll-amount = "0%"; }) + (plain "tablet" [ + (leaf "map-to-output" "DP-2") + ]) + ]) + + # Laptop monitor + (node "output" "eDP-1" [ + (leaf "mode" "1920x1080@59.999") + (leaf "scale" 1) + (leaf "position" { + x = 0; + y = 0; + }) + ]) + + # PC monitors + (node "output" "DP-2" [ + (leaf "mode" "1920x1080@59.999") + (leaf "scale" 1) + (leaf "position" { + x = 0; + y = 0; + }) + ]) + (node "output" "HDMI-A-1" [ + (leaf "mode" "1920x1080@59.999") + (leaf "scale" 1) + (leaf "position" { + x = 1920; + y = 0; + }) + ]) + + (plain "layout" [ + (leaf "gaps" 0) + (leaf "center-focused-column" "on-overflow") + + (plain "focus-ring" [ + (leaf "width" 2) + (leaf "active-color" "#f9e2af") + (leaf "inactive-color" "transparent") + (leaf "active-gradient" { + from = "#E5989B"; + to = "#FFB4A2"; + angle = 45; + relative-to = "workspace-view"; + "in" = "oklch longer hue"; + }) + ]) + + (plain "border" [ + (flag "off") + ]) + (plain "shadow" [ + # (flag "on") + ]) + (plain "tab-indicator" [ + (leaf "width" 2) + (leaf "gap" 4) + (leaf "gaps-between-tabs" 2) + ]) + (plain "insert-hint" [ + (leaf "color" "#ffc87f80") + (leaf "gradient" { + from = "#f38ba880"; + to = "#f9e2af80"; + angle = 45; + relative-to = "workspace-view"; + "in" = "oklch longer hue"; + }) + ]) + (plain "preset-column-widths" ( + map (width: (leaf "proportion" width)) [ + 0.3333 + 0.5 + 0.66666 + ] + )) + (plain "default-column-width" [ + (leaf "proportion" 0.5) + ]) + (leaf "background-color" "transparent") + ]) + (leaf "spawn-at-startup" "waybar") + (plain "environment" [ + (leaf "DISPLAY" ":0") + ]) + (plain "layer-rule" [ + (leaf "match" { namespace = "overview$"; }) + (leaf "place-within-backdrop" true) + ]) + (flag "prefer-no-csd") + (plain "switch-events" [ + (plain "lid-close" [ + (leaf "spawn" <| getExe pkgs.swaylock) + ]) + ]) + (plain "overview" [ + (leaf "zoom" 0.6) + (leaf "backdrop-color" "#777777") + ]) + + (plain "animations" [ + (plain "window-close" [ + (leaf "duration-ms" 250) + (leaf "curve" "linear") + (leaf "custom-shader" <| readFile ./window-close.glsl) + ]) + ]) + + (plain "window-rule" [ + (leaf "draw-border-with-background" false) + ]) + (plain "debug" [ + (flag "wait-for-frame-completion-in-pipewire") + ]) + (plain "hotkey-overlay" [ + (flag "skip-at-startup") + ]) + (plain "cursor" [ + (leaf "xcursor-theme" "BreezeX-RosePine-Linux") + (leaf "xcursor-size" 32) + (flag "hide-when-typing") + ]) + + (plain "binds" [ + (plain "XF86AudioRaiseVolume" [ + (leaf "spawn" [ + "volumectl" + "-u" + "up" + ]) + ]) + (plain "XF86AudioLowerVolume" [ + (leaf "spawn" [ + "volumectl" + "-u" + "down" + ]) + ]) + (plain "XF86AudioMute" [ + (leaf "spawn" [ + "volumectl" + "toggle-mute" + ]) + ]) + (plain "XF86AudioMicMute" [ + (leaf "spawn" [ + "volumectl" + "-m" + "toggle-mute" + ]) + ]) + (plain "XF86AudioPlay" [ + (leaf "spawn" [ + "playerctl" + "play-pause" + ]) + ]) + (plain "XF86AudioNext" [ + (leaf "spawn" [ + "playerctl" + "next" + ]) + ]) + (plain "XF86AudioPrev" [ + (leaf "spawn" [ + "playerctl" + "previous" + ]) + ]) + (plain "XF86MonBrightnessUp" [ + (leaf "spawn" [ + "lightctl" + "up" + ]) + ]) + (plain "XF86MonBrightnessDown" [ + (leaf "spawn" [ + "lightctl" + "down" + ]) + ]) + (plain "Mod+Shift+Slash" [ (flag "show-hotkey-overlay") ]) + (plain "Mod+Return" [ (leaf "spawn" <| getExe pkgs.ghostty) ]) + (plain "Mod+Shift+Return" [ + (leaf "spawn" [ + (getExe pkgs.bash) + "-c" + "${getExe pkgs.niri} msg action spawn -- ${getExe pkgs.ghostty}; sleep 0.2; ${getExe pkgs.niri} msg action consume-or-expel-window-left" + ]) + ]) + + (plain "Ctrl+Print" [ (flag "screenshot-screen") ]) + (plain "Mod+0" [ (leaf "focus-workspace" 0) ]) + (plain "Mod+1" [ (leaf "focus-workspace" 1) ]) + (plain "Mod+2" [ (leaf "focus-workspace" 2) ]) + (plain "Mod+3" [ (leaf "focus-workspace" 3) ]) + (plain "Mod+4" [ (leaf "focus-workspace" 4) ]) + (plain "Mod+5" [ (leaf "focus-workspace" 5) ]) + (plain "Mod+6" [ (leaf "focus-workspace" 6) ]) + (plain "Mod+7" [ (leaf "focus-workspace" 7) ]) + (plain "Mod+8" [ (leaf "focus-workspace" 8) ]) + (plain "Mod+9" [ (leaf "focus-workspace" 9) ]) + (plain "Mod+Alt+L" [ (leaf "spawn" <| getExe pkgs.swaylock) ]) + (plain "Mod+B" [ (leaf "spawn" <| getExe pkgs.brave) ]) + (plain "Mod+BracketLeft" [ (flag "consume-or-expel-window-left") ]) + (plain "Mod+BracketRight" [ (flag "consume-or-expel-window-right") ]) + (plain "Mod+C" [ (flag "center-column") ]) + (plain "Mod+Comma" [ (flag "consume-window-into-column") ]) + (plain "Mod+Ctrl+End" [ (flag "move-column-to-last") ]) + (plain "Mod+Ctrl+F" [ (flag "expand-column-to-available-width") ]) + (plain "Mod+Ctrl+H" [ (flag "focus-monitor-left") ]) + (plain "Mod+Ctrl+Home" [ (flag "move-column-to-first") ]) + (plain "Mod+Ctrl+J" [ (flag "focus-monitor-down") ]) + (plain "Mod+Ctrl+K" [ (flag "focus-monitor-up") ]) + (plain "Mod+Ctrl+L" [ (flag "focus-monitor-right") ]) + (plain "Mod+Ctrl+R" [ (flag "reset-window-height") ]) + (plain "Mod+D" [ (leaf "spawn" <| getExe pkgs.fuzzel) ]) + (plain "Mod+End" [ (flag "focus-column-last") ]) + (plain "Mod+Equal" [ (leaf "set-column-width" [ "+10%" ]) ]) + (plain "Mod+F" [ (flag "maximize-column") ]) + (plain "Mod+H" [ (flag "focus-column-or-monitor-left") ]) + (plain "Mod+Home" [ (flag "focus-column-first") ]) + (plain "Mod+I" [ (flag "focus-workspace-up") ]) + (plain "Mod+J" [ (flag "focus-window-or-workspace-down") ]) + (plain "Mod+K" [ (flag "focus-window-or-workspace-up") ]) + (plain "Mod+L" [ (flag "focus-column-or-monitor-right") ]) + (plain "Mod+Minus" [ (leaf "set-column-width" [ "-10%" ]) ]) + (plain "Mod+O" [ (flag "toggle-overview") ]) + (plain "Mod+Page_Down" [ (flag "focus-workspace-down") ]) + (plain "Mod+Page_Up" [ (flag "focus-workspace-up") ]) + (plain "Mod+Period" [ (flag "expel-window-from-column") ]) + (plain "Mod+Q" [ (flag "close-window") ]) + (plain "Mod+R" [ (flag "switch-preset-column-width") ]) + (plain "Mod+Shift+0" [ (leaf "move-column-to-workspace" 0) ]) + (plain "Mod+Shift+1" [ (leaf "move-column-to-workspace" 1) ]) + (plain "Mod+Shift+2" [ (leaf "move-column-to-workspace" 2) ]) + (plain "Mod+Shift+3" [ (leaf "move-column-to-workspace" 3) ]) + (plain "Mod+Shift+4" [ (leaf "move-column-to-workspace" 4) ]) + (plain "Mod+Shift+5" [ (leaf "move-column-to-workspace" 5) ]) + (plain "Mod+Shift+6" [ (leaf "move-column-to-workspace" 6) ]) + (plain "Mod+Shift+7" [ (leaf "move-column-to-workspace" 7) ]) + (plain "Mod+Shift+8" [ (leaf "move-column-to-workspace" 8) ]) + (plain "Mod+Shift+9" [ (leaf "move-column-to-workspace" 9) ]) + (plain "Mod+Shift+Ctrl+Down" [ (flag "move-column-to-monitor-down") ]) + (plain "Mod+Shift+Ctrl+H" [ (flag "move-column-to-monitor-left") ]) + (plain "Mod+Shift+Ctrl+J" [ (flag "move-column-to-monitor-down") ]) + (plain "Mod+Shift+Ctrl+K" [ (flag "move-column-to-monitor-up") ]) + (plain "Mod+Shift+Ctrl+Left" [ (flag "move-column-to-monitor-left") ]) + (plain "Mod+Shift+Ctrl+L" [ (flag "move-column-to-monitor-right") ]) + (plain "Mod+Shift+Ctrl+Right" [ (flag "move-column-to-monitor-right") ]) + (plain "Mod+Shift+Ctrl+Up" [ (flag "move-column-to-monitor-up") ]) + (plain "Mod+Shift+E" [ (flag "quit") ]) + (plain "Mod+Shift+Equal" [ (leaf "set-window-height" [ "+10%" ]) ]) + (plain "Mod+Shift+F" [ (flag "fullscreen-window") ]) + (plain "Mod+Shift+H" [ (flag "move-column-left-or-to-monitor-left") ]) + (plain "Mod+Shift+I" [ (flag "move-column-to-workspace-up") ]) + (plain "Mod+Shift+J" [ (flag "move-window-down-or-to-workspace-down") ]) + (plain "Mod+Shift+K" [ (flag "move-window-up-or-to-workspace-up") ]) + (plain "Mod+Shift+L" [ (flag "move-column-right-or-to-monitor-right") ]) + (plain "Mod+Shift+Minus" [ (leaf "set-window-height" [ "-10%" ]) ]) + (plain "Mod+Shift+Page_Down" [ (flag "move-column-to-workspace-down") ]) + (plain "Mod+Shift+Page_Up" [ (flag "move-column-to-workspace-up") ]) + (plain "Mod+Shift+P" [ (flag "power-off-monitors") ]) + (plain "Mod+Shift+R" [ (flag "switch-preset-window-height") ]) + (plain "Mod+Shift+U" [ (flag "move-column-to-workspace-down") ]) + (plain "Mod+Shift+V" [ (flag "switch-focus-between-floating-and-tiling") ]) + (plain "Mod+Shift+WheelScrollDown" [ (flag "move-column-to-workspace-down") ]) + (plain "Mod+Shift+WheelScrollLeft" [ (flag "move-column-left") ]) + (plain "Mod+Shift+WheelScrollRight" [ (flag "move-column-right") ]) + (plain "Mod+Shift+WheelScrollUp" [ (flag "move-column-to-workspace-up") ]) + (plain "Mod+T" [ (flag "screenshot") ]) + (plain "Mod+U" [ (flag "focus-workspace-down") ]) + (plain "Mod+V" [ (flag "toggle-window-floating") ]) + (plain "Mod+W" [ (flag "toggle-column-tabbed-display") ]) + (plain "Mod+WheelScrollDown" [ (flag "focus-workspace-down") ]) + (plain "Mod+WheelScrollLeft" [ (flag "focus-column-left") ]) + (plain "Mod+WheelScrollRight" [ (flag "focus-column-right") ]) + (plain "Mod+WheelScrollUp" [ (flag "focus-workspace-up") ]) + (plain "Print" [ (flag "screenshot") ]) + + ]) +] +++ (map + ( + app-id: + (plain "window-rule" [ + (leaf "match" { inherit app-id; }) + (leaf "open-floating" true) + ]) + ) + [ + "unset" + "org.gnome.Nautilus" + "org.freedesktop.impl.portal.desktop.kde" + ] +) diff --git a/modules/wms/niri/kdl.nix b/modules/wms/niri/kdl.nix new file mode 100644 index 0000000..606f97a --- /dev/null +++ b/modules/wms/niri/kdl.nix @@ -0,0 +1,323 @@ +# https://github.com/NixOS/nixpkgs/pull/426828 +# The KDL document language (https://kdl.dev/) +/* + Original file: formats.nix + + Copyright (c) 2003-2025 Eelco Dolstra and the Nixpkgs/NixOS contributors + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +/* + * Modificatied by faukah (2025) + * + * This modified version is part of the Nichts project and is licensed under + * the GNU General Public License v3.0. + * + * See for details. +*/ +{ + lib, + pkgs, + ... +}: +let + + inherit (lib.types) + listOf + attrsOf + str + bool + number + oneOf + nullOr + submodule + coercedTo + path + ; + inherit (lib.lists) isList; + inherit (lib.attrsets) isAttrs; + inherit (lib.trivial) isBool; +in +{ + type = ( + let + mergeUniq = + mergeOne: + lib.mergeUniqueOption { + message = ""; + merge = + loc: defs: + let + inherit (lib.head defs) file value; + in + mergeOne file loc value; + }; + + mergeFlat = + elemType: loc: file: value: + if value ? _type then + throw "${lib.showOption loc} has wrong type: expected '${elemType.description}', got `${value._type}`" + else + elemType.merge loc [ { inherit file value; } ]; + + uniqFlatListOf = + elemType: + lib.mkOptionType { + name = "uniqFlatListOf"; + inherit (listOf elemType) description descriptionClass; + check = isList; + merge = mergeUniq ( + file: loc: lib.imap1 (i: mergeFlat elemType (loc ++ [ "[entry ${toString i}]" ]) file) + ); + }; + + uniqFlatAttrsOf = + elemType: + lib.mkOptionType { + name = "uniqFlatAttrsOf"; + inherit (attrsOf elemType) description descriptionClass; + check = isAttrs; + merge = mergeUniq (file: loc: lib.mapAttrs (name: mergeFlat elemType (loc ++ [ name ]) file)); + }; + + kdlUntypedValue = lib.mkOptionType { + name = "kdlUntypedValue"; + description = "KDL value without type annotation"; + descriptionClass = "noun"; + + inherit + (nullOr (oneOf [ + str + bool + number + path + ])) + check + merge + ; + }; + + kdlTypedValue = lib.mkOptionType { + name = "kdlTypedValue"; + description = "KDL value with type annotation"; + descriptionClass = "noun"; + + check = isAttrs; + merge = + (submodule { + options = { + type = lib.mkOption { + type = nullOr str; + default = null; + description = '' + [Type annotation](https://kdl.dev/spec/#name-type-annotation) of a [KDL value](https://kdl.dev/spec/#name-value). + ''; + }; + value = lib.mkOption { + type = kdlUntypedValue; + description = '' + Scalar part of a [KDL value](https://kdl.dev/spec/#name-value) + ''; + }; + }; + }).merge; + }; + + # https://kdl.dev/spec/#name-value + kdlValue = lib.mkOptionType { + name = "kdlValue"; + description = "KDL value"; + descriptionClass = "noun"; + + inherit (coercedTo kdlUntypedValue (value: { inherit value; }) kdlTypedValue) check merge; + + nestedTypes = { + type = nullOr str; + scalar = kdlUntypedValue; + }; + }; + + # https://kdl.dev/spec/#name-node + kdlNode = lib.mkOptionType { + name = "kdlNode"; + description = "KDL node"; + descriptionClass = "noun"; + + check = isAttrs; + merge = + (submodule { + options = { + type = lib.mkOption { + type = nullOr str; + default = null; + description = '' + [Type annotation](https://kdl.dev/spec/#name-type-annotation) of a KDL node. + ''; + }; + name = lib.mkOption { + type = str; + description = '' + Name of a [KDL node](https://kdl.dev/spec/#name-node). + ''; + }; + arguments = lib.mkOption { + type = uniqFlatListOf kdlValue; + default = [ ]; + description = '' + [Arguments](https://kdl.dev/spec/#name-argument) of a KDL node. + ''; + }; + properties = lib.mkOption { + type = uniqFlatAttrsOf kdlValue; + default = { }; + description = '' + [Properties](https://kdl.dev/spec/#name-property) of a KDL node. + ''; + }; + children = lib.mkOption { + type = kdlDocument; + default = [ ]; + description = '' + [Children](https://kdl.dev/spec/#children-block) of a KDL node. + ''; + }; + }; + }).merge; + + nestedTypes = { + name = str; + type = nullOr str; + arguments = uniqFlatListOf kdlValue; + properties = uniqFlatAttrsOf kdlValue; + children = kdlDocument; + }; + }; + + kdlDocument = lib.mkOptionType { + name = "kdlDocument"; + description = "KDL document"; + descriptionClass = "noun"; + + check = isList; + merge = mergeUniq ( + file: + let + mergeDocument = + loc: toplevel: + builtins.concatLists ( + lib.imap1 (i: mergeDocumentEntry (loc ++ [ "[entry ${toString i}]" ])) toplevel + ); + + mergeDocumentEntry = + loc: value: + let + inherit (lib.options) showDefs; + defs = [ { inherit file value; } ]; + in + if isList value then + mergeDocument loc value + else if value ? _type then + if value._type == "if" then + if isBool value.condition then + if value.condition then mergeDocumentEntry loc value.content else [ ] + else + throw "`mkIf` called with non-Boolean condition at ${lib.showOption loc}. Definition value:${showDefs defs}" + else if value._type == "merge" then + throw '' + ${lib.showOption loc} has wrong type: expected a KDL node or document, got 'merge'. + note: `mkMerge` is potentially ambiguous in a KDL document, as "merging" is application-specific. if you intended to "splat" all the nodes in a KDL document, you can just insert the list of nodes directly. you can arbitrarily nest KDL documents, and they will be concatenated. + '' + else + throw "${lib.showOption loc} has wrong type: expected a KDL node or document, got '${value._type}'. Definition value:${showDefs defs}" + else if kdlNode.check value then + [ (kdlNode.merge loc [ { inherit file value; } ]) ] + else + throw "${lib.showOption loc} has wrong type: expected a KDL node or document. Definition value:${showDefs defs}"; + in + mergeDocument + ); + + nestedTypes.node = kdlNode; + }; + in + kdlDocument + ); + + lib = { + /** + Helper function for generating attrsets expected by pkgs.formats.kdl + # Example + ```nix + let + settingsFormat = pkgs.formats.kdl { }; + inherit (settingsFormat.lib) node; + in + settingsFormat.generate "sample.kdl" [ + (node "foo" null [ ] { } [ + (node "bar" null [ "baz" ] { a = 1; } [ ]) + ]) + ] + ``` + # Arguments + name + : The name of the node, represented by a string + type + : The type annotation of the node, represented by a string, or null to avoid generating a type annotation + arguments + : The arguments of the node, represented as a list of KDL values + properties + : The properties of the node, represented as an attrset of KDL values + children + : The children of the node, represented as a list of nodes + */ + node = name: type: arguments: properties: children: { + inherit + name + type + arguments + properties + children + ; + }; + + /** + Helper function for generating the format of a typed value as expected by pkgs.formats.kdl + type + : The type of the value, represented by a string + value + : The value itself + */ + typed = type: value: { inherit type value; }; + }; + + generate = + name: value: + pkgs.callPackage ( + { runCommand, jsonkdl }: + runCommand name + { + nativeBuildInputs = [ jsonkdl ]; + value = builtins.toJSON value; + passAsFile = [ "value" ]; + } + '' + jsonkdl --kdl-v1 -- "$valuePath" "$out" + '' + ) { }; +} diff --git a/modules/wms/niri/niri.mod.nix b/modules/wms/niri/niri.mod.nix index 0e45e4e..d110264 100644 --- a/modules/wms/niri/niri.mod.nix +++ b/modules/wms/niri/niri.mod.nix @@ -102,6 +102,48 @@ let } ) { }; + + kdl = pkgs.callPackage ./kdl.nix { }; + + node = name: args: children: { + inherit name; + inherit + (lib.foldl + ( + self: arg: + if lib.isAttrs arg then + self // { properties = self.properties // arg; } + else + self // { arguments = self.arguments ++ [ arg ]; } + ) + { + arguments = [ ]; + properties = { }; + } + (lib.toList args) + ) + arguments + properties + ; + inherit children; + }; + + plain = name: node name [ ]; + leaf = name: args: node name args [ ]; + flag = name: node name [ ] [ ]; + + niri-config = kdl.generate "niri-config.kdl" ( + import ./config.nix { + inherit + node + plain + leaf + flag + lib + pkgs + ; + } + ); in { options.modules.desktops.niri.enable = mkEnableOption "Niri, a scolling tiling wayland compositor"; @@ -115,7 +157,7 @@ in # which is something I direly want to avoid. services.gnome.gnome-keyring.enable = mkForce false; - hjem.users.${username}.files.".config/niri/config.kdl".source = ./config.kdl; + hjem.users.${username}.files.".config/niri/config.kdl".source = niri-config; environment.systemPackages = builtins.attrValues { inherit (pkgs)