From 5357ba307b9db30a06631423529db57da4c790cc Mon Sep 17 00:00:00 2001 From: OlivierChiasson Date: Mon, 13 Jul 2026 12:38:19 -0300 Subject: [PATCH] Fix dms-plugins - Transitioned to an auto-derived plugin registry from flake inputs, simplifying the addition of new plugins by requiring edits only in `flake.nix`. - Implemented a camelCase transformation for plugin IDs to align with upstream conventions, with exceptions for specific plugins. - Enhanced the `shipPlugin` function to route plugin sources correctly, ensuring compatibility with the DMS structure. - Added assertions to validate Obsidian vault paths at build time, improving error handling and user guidance. --- modules/desktop/shells/dms/_private/hm.nix | 99 ++++++++++++++++------ 1 file changed, 73 insertions(+), 26 deletions(-) diff --git a/modules/desktop/shells/dms/_private/hm.nix b/modules/desktop/shells/dms/_private/hm.nix index 8663546..eff3531 100644 --- a/modules/desktop/shells/dms/_private/hm.nix +++ b/modules/desktop/shells/dms/_private/hm.nix @@ -124,33 +124,66 @@ let ; }; - thirdPartyPlugins = { - dankVault = inputs.dms-plugin-dank-vault; - calculator = inputs.dms-plugin-calculator; - homeAssistantMonitor = inputs.dms-plugin-home-assistant; - dropdownMenu = inputs.dms-plugin-dropdown-menu; - ocrScanner = inputs.dms-plugin-ocr-scanner; - unifiedTaskbar = inputs.dms-plugin-unified-taskbar; - widgetGroup = inputs.dms-plugin-widget-group; - nixPackageRunner = inputs.dms-plugin-nix-package-runner; - ambientSound = inputs.dms-plugin-ambient-sound; - cavaVisualizer = inputs.dms-plugin-cava-visualizer; - emojiLauncher = inputs.dms-plugin-emoji-launcher; - dankDesktopWeather = inputs.dms-plugin-official + "/DankDesktopWeather"; - webSearch = inputs.dms-plugin-web-search; - wallpaperCarousel = inputs.dms-plugin-wallpaper-carousel; - ephemera = inputs.dms-plugin-ephemera; - appShortcut = inputs.dms-plugin-app-shortcut; - wvkbdToggle = inputs.dms-plugin-wvkbd-toggle; - rbwLockToggle = inputs.dms-plugin-rbw-lock-toggle; - }; + # Plugin registry auto-derived from flake inputs matching `dms-plugin-*`. + # Adding a plugin now requires editing only `flake.nix`. The on-disk + # plugin id (= path under ~/.config/DankMaterialShell/plugins/) is camelCase + # per upstream convention; the kebab→camel transform matches it. The + # `idExceptions` map carries the one plugin whose manifest id does not + # follow the default rule. + pluginInputs = lib.filterAttrs (n: _: lib.hasPrefix "dms-plugin-" n) inputs; - shipPlugin = - _id: src: - { - source = src; - onChange = "${dmsRestartOnceScript}"; + # `dank-vault` → `dankVault`. `lib.splitString` yields ≥ 1 element so + # `head parts` is safe; `map` runs over the tail only (no-op for + # single-word names like `calculator`). `builtins.substring 1 (-1) p` + # returns the rest of `p` from index 1, dropping the first char + # (Nix treats a negative `len` as "rest of string from `start`"). + toCamel = s: + let parts = lib.splitString "-" s; in + builtins.head parts + + lib.concatStrings (map ( + p: if p == "" then "" + else lib.toUpper (builtins.substring 0 1 p) + + builtins.substring 1 (-1) p + ) (builtins.tail parts)); + + # The `home-assistant` plugin ships its manifest under id + # `homeAssistantMonitor` (not the default kebab→camel result). + idExceptions = { "home-assistant" = "homeAssistantMonitor"; }; + + # NB: don't rewrite as `idExceptions.${stripped} or toCamel stripped`. + # Nix grammar: `or` binds tighter than function application, so the + # `toCamel` and its arg parse as separate postfix args to the select. + # When the lookup succeeds the resolved string is then applied as a + # function, producing `attempt to call something which is not a function + # but a string: "homeAssistantMonitor"`. Explicit `if/hasAttr` sidesteps + # the parse entirely. + camelMap = lib.mapAttrs' (n: src: + let stripped = lib.removePrefix "dms-plugin-" n; in + lib.nameValuePair + (if builtins.hasAttr stripped idExceptions + then idExceptions.${stripped} + else toCamel stripped) + src + ) pluginInputs; + + # The official plugin pack bundles multiple QML apps. Ship only the + # DankDesktopWeather subdir (verified by its manifest) to slim closure + # and avoid overlapping with future dedicated `dms-plugin-*` flakes. + thirdPartyPlugins = + builtins.removeAttrs camelMap [ "official" ] // { + dankDesktopWeather = inputs.dms-plugin-official + "/DankDesktopWeather"; }; + + # DMS reads plugins from ~/.config/DankMaterialShell/plugins//, so + # we route each plugin source there via HM's `xdg.configFile.target`. + # The attrset name is scoped under `dms-plugin-${id}` (not the bare + # camelCase id) so unrelated HM modules can ship a same-named file + # (e.g. `xdg.configFile.calculator`) without colliding with us. + shipPlugin = id: src: { + source = src; + target = "DankMaterialShell/plugins/${id}"; + onChange = "${dmsRestartOnceScript}"; + }; in { imports = [ @@ -160,7 +193,8 @@ in config = lib.mkIf dmsEnabled (lib.mkMerge [ (lib.mkIf (dmsOs.bundleThirdPartyPlugins or true) { - xdg.configFile = lib.mapAttrs (_id: src: shipPlugin _id src) thirdPartyPlugins; + xdg.configFile = lib.mapAttrs' (id: src: lib.nameValuePair + "dms-plugin-${id}" (shipPlugin id src)) thirdPartyPlugins; }) { programs.nix-monitor = { @@ -203,10 +237,23 @@ in enableDynamicTheming = true; enableAudioWavelength = true; enableCalendarEvents = false; + # Empty on purpose: DMS owns ~/.config/DankMaterialShell/{settings,session}.json + # at runtime (seeded by `home.activation.dmsSeedConfig`). Setting these + # to non-empty here would clobber the runtime seed on every activation. settings = { }; session = { }; }; + # Surface bad obsidianVaults paths at build time instead of at first matugen run. + # Each entry must point at the `/.obsidian` dir (matugen writes + # `/.obsidian/snippets/matugen.css` from there). + assertions = lib.mkIf ((dmsOs.obsidianVaults or [ ]) != [ ]) [ + { + assertion = builtins.all (v: lib.hasSuffix "/.obsidian" v) (dmsOs.obsidianVaults or [ ]); + message = "chiasson.desktop.shells.dms.obsidianVaults entries must end in '/.obsidian' (matugen writes /.obsidian/snippets/matugen.css). Example: /home/olivier/Documents/HomeLab/.obsidian"; + } + ]; + home.activation.dmsSeedConfig = lib.hm.dag.entryAfter [ "writeBoundary" ] "${dmsSeedConfigScript}"; systemd.user.services.dms.serviceConfig.ExecStartPre =