{ config, pkgs, lib, ... }: let cfg = config.programs.obsidian; corePlugins = [ "audio-recorder" "backlink" "bookmarks" "canvas" "command-palette" "daily-notes" "editor-status" "file-explorer" "file-recovery" "global-search" "graph" "markdown-importer" "note-composer" "outgoing-link" "outline" "page-preview" "properties" "publish" "random-note" "slash-command" "slides" "switcher" "sync" "tag-pane" "templates" "word-count" "workspaces" "zk-prefixer" ]; in { options.programs.obsidian = with lib; with types; { enable = mkEnableOption "obsidian"; package = mkPackageOption pkgs "obsidian" { }; sharedSettings = { app = mkOption { description = "Settings to write to app.json."; type = raw; default = { }; }; appearance = mkOption { description = "Settings to write to appearance.json."; type = raw; default = { }; }; corePlugins = mkOption { description = "Core plugins to activate."; type = raw; default = [ "backlink" "bookmarks" "canvas" "command-palette" "daily-notes" "editor-status" "file-explorer" "file-recovery" "global-search" "graph" "note-composer" "outgoing-link" "outline" "page-preview" "switcher" "tag-pane" "templates" "word-count" ]; }; }; vaults = mkOption { description = "List of vaults to create."; type = attrsOf ( submodule ( { name, config, ... }: { options = { enable = mkOption { type = bool; default = true; description = "Whether this vault should be generated."; }; target = mkOption { type = str; defaultText = literalExpression "name"; description = "Path to target vault relative to the user's {env}`HOME`."; }; settings = { app = mkOption { description = "Settings to write to app.json."; type = attrsOf anything; default = cfg.sharedSettings.app; }; appearance = mkOption { description = "Settings to write to appearance.json."; type = attrsOf anything; default = cfg.sharedSettings.appearance; }; corePlugins = mkOption { description = "Core plugins to activate."; type = listOf (enum corePlugins); default = cfg.sharedSettings.corePlugins; }; }; }; config.target = mkDefault name; } ) ); default = { }; }; }; config = let vaults = builtins.filter (vault: vault.enable == true) (builtins.attrValues cfg.vaults); in lib.mkIf cfg.enable { home = { packages = [ cfg.package ]; file = let mkApp = vault: { name = "${vault.target}/.obsidian/app.json"; value = { source = (pkgs.formats.json { }).generate "app.json" vault.settings.app; }; }; mkAppearance = vault: { name = "${vault.target}/.obsidian/appearance.json"; value = { source = (pkgs.formats.json { }).generate "appearance.json" vault.settings.appearance; }; }; mkCorePlugins = vault: [ { name = "${vault.target}/.obsidian/core-plugins.json"; value = { source = (pkgs.formats.json { }).generate "core-plugins.json" vault.settings.corePlugins; }; } { name = "${vault.target}/.obsidian/core-plugins-migration.json"; value = { source = (pkgs.formats.json { }).generate "core-plugins-migration.json" ( builtins.listToAttrs ( builtins.map (plugin: { name = plugin; value = builtins.elem plugin vault.settings.corePlugins; }) corePlugins ) ); }; } ]; in builtins.listToAttrs ( lib.lists.flatten ( builtins.map (vault: [ (mkApp vault) (mkAppearance vault) (mkCorePlugins vault) ]) vaults ) ); }; xdg.configFile."obsidian/obsidian.json".source = (pkgs.formats.json { }).generate "obsidian.json" { vaults = builtins.listToAttrs ( builtins.map (vault: { name = builtins.hashString "md5" vault.target; value = { path = "${config.home.homeDirectory}/${vault.target}"; } // (lib.attrsets.optionalAttrs ((builtins.length vaults) == 1) { open = true; }); }) vaults ); }; }; }