From 124f6ab29204befad30ecda7eba4a23630121c01 Mon Sep 17 00:00:00 2001 From: Nikolaos Karaolidis Date: Fri, 12 Jul 2024 12:54:13 +0300 Subject: [PATCH] Refactor obsidian options module Signed-off-by: Nikolaos Karaolidis --- .../user/configs/gui/obsidian/default.nix | 24 +- .../user/configs/gui/obsidian/options.nix | 215 ++++++++++++++---- .../obsidian/snippets/editor-monospace.css | 3 - hosts/common/user/configs/options.nix | 16 +- 4 files changed, 192 insertions(+), 66 deletions(-) delete mode 100644 hosts/common/user/configs/gui/obsidian/snippets/editor-monospace.css diff --git a/hosts/common/user/configs/gui/obsidian/default.nix b/hosts/common/user/configs/gui/obsidian/default.nix index 9b7cf33..2ce09e3 100644 --- a/hosts/common/user/configs/gui/obsidian/default.nix +++ b/hosts/common/user/configs/gui/obsidian/default.nix @@ -48,14 +48,26 @@ "tag-pane" ]; - plugins = [ (import ./plugins/minimal-settings.nix { inherit pkgs; }) ]; - - cssSnippets = [ - ./snippets/editor-monospace.css - ./snippets/file-explorer-separators.css + plugins = [ + { + pkg = import ./plugins/minimal-settings.nix { inherit pkgs; }; + extraFiles."data.json".source = (pkgs.formats.json { }).generate "data.json" { + labeledNav = true; + editorFont = "var(--font-monospace)"; + }; + } ]; - theme = import ./themes/minimal.nix { inherit pkgs; }; + cssSnippets = { + "file-explorer-separators".source = ./snippets/file-explorer-separators.css; + }; + + themes = [ + { + enable = true; + pkg = import ./themes/minimal.nix { inherit pkgs; }; + } + ]; }; }; diff --git a/hosts/common/user/configs/gui/obsidian/options.nix b/hosts/common/user/configs/gui/obsidian/options.nix index fe5c84d..2979801 100644 --- a/hosts/common/user/configs/gui/obsidian/options.nix +++ b/hosts/common/user/configs/gui/obsidian/options.nix @@ -42,6 +42,103 @@ in options.programs.obsidian = with lib; with types; + let + cssSnippetsOptions = + { name, config, ... }: + { + options = { + enable = mkOption { + type = bool; + default = true; + description = "Whether to enable the snippet."; + }; + + name = mkOption { + type = str; + defaultText = literalExpression "name"; + description = "Name of the snippet."; + }; + + source = mkOption { + type = addCheck path (path: if path != null then lib.filesystem.pathIsRegularFile path else true); + description = "Path of the source file."; + }; + + text = mkOption { + type = str; + description = "Text of the file."; + }; + }; + + config.name = mkDefault name; + }; + + pluginsExtraFilesOptions = + { name, config, ... }: + { + options = { + source = mkOption { + type = path; + description = "Path of the source file or directory."; + }; + + text = mkOption { + type = str; + description = "Text of the file."; + }; + + target = mkOption { + type = str; + defaultText = literalExpression "name"; + description = "Path to target relative to the plugin directory."; + }; + }; + + config.target = mkIf (config ? text) (mkDefault name); + }; + + pluginsOptions = + { config, ... }: + { + options = { + enable = mkOption { + type = bool; + default = true; + description = "Whether to enable the plugin."; + }; + + pkg = mkOption { + type = package; + description = "The plugin package."; + }; + + extraFiles = mkOption { + type = attrsOf (submodule pluginsExtraFilesOptions); + description = "Additional files to include in the plugin directory."; + }; + }; + }; + + themesOptions = + { config, ... }: + { + options = { + enable = mkOption { + type = bool; + default = false; + description = '' + Whether to set the theme as active. + Only one theme can be active at a time. + ''; + }; + + pkg = mkOption { + type = package; + description = "The theme package."; + }; + }; + }; + in { enable = mkEnableOption "obsidian"; package = mkPackageOption pkgs "obsidian" { }; @@ -84,22 +181,22 @@ in ]; }; - plugins = mkOption { - description = "Community plugins to activate."; - type = raw; - default = [ ]; - }; - cssSnippets = mkOption { description = "CSS snippets to install."; type = raw; + default = { }; + }; + + plugins = mkOption { + description = "Community plugins to install and activate."; + type = raw; default = [ ]; }; - theme = mkOption { - description = "Obsidian theme package."; + themes = mkOption { + description = "Themes to install."; type = raw; - default = null; + default = [ ]; }; }; @@ -141,22 +238,22 @@ in default = cfg.sharedSettings.corePlugins; }; - plugins = mkOption { - description = "Community plugins to activate."; - type = listOf package; - default = cfg.sharedSettings.plugins; - }; - cssSnippets = mkOption { description = "CSS snippets to install."; - type = listOf path; + type = attrsOf (submodule cssSnippetsOptions); default = cfg.sharedSettings.cssSnippets; }; - theme = mkOption { - description = "Obsidian theme package."; - type = nullOr package; - default = cfg.sharedSettings.theme; + plugins = mkOption { + description = "Community plugins to install and activate."; + type = listOf (submodule pluginsOptions); + default = cfg.sharedSettings.plugins; + }; + + themes = mkOption { + description = "Themes to install."; + type = listOf (submodule themesOptions); + default = cfg.sharedSettings.themes; }; }; }; @@ -172,13 +269,13 @@ in config = let vaults = builtins.filter (vault: vault.enable == true) (builtins.attrValues cfg.vaults); - getManifestId = + readDir = dir: builtins.attrNames (builtins.readDir dir); + getManifest = pkg: let manifest = builtins.fromJSON (builtins.readFile "${pkg}/manifest.json"); in manifest.id or manifest.name; - readDir = dir: builtins.attrNames (builtins.readDir dir); in lib.mkIf cfg.enable { home = { @@ -192,22 +289,29 @@ in 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 - // { - enabledCssSnippets = builtins.map ( - snippet: lib.strings.removeSuffix ".css" (builtins.baseNameOf snippet) - ) vault.settings.cssSnippets; - } - // lib.attrsets.optionalAttrs (vault.settings.theme != null) { - cssTheme = getManifestId vault.settings.theme; - } - ); - }; + value = + let + enabledSnippets = builtins.filter (snippet: snippet.enable) ( + builtins.attrValues vault.settings.cssSnippets + ); + activeTheme = lib.lists.findSingle ( + theme: theme.enable + ) null (throw "Only one theme can be enabled at a time.") vault.settings.themes; + in + { + source = (pkgs.formats.json { }).generate "appearance.json" ( + vault.settings.appearance + // { + enabledCssSnippets = builtins.map (snippet: snippet.name) enabledSnippets; + } + // lib.attrsets.optionalAttrs (activeTheme != null) { cssTheme = getManifest activeTheme.pkg; } + ); + }; }; + mkCorePlugins = vault: [ { name = "${vault.target}/.obsidian/core-plugins.json"; @@ -229,14 +333,18 @@ in }; } ]; + mkCommunityPlugins = vault: + let + enabledPlugins = builtins.filter (plugin: plugin.enable) vault.settings.plugins; + in [ { name = "${vault.target}/.obsidian/community-plugins.json"; value = { source = (pkgs.formats.json { }).generate "community-plugins.json" ( - builtins.map getManifestId vault.settings.plugins + builtins.map (plugin: getManifest plugin.pkg) enabledPlugins ); }; } @@ -255,28 +363,35 @@ in ++ builtins.map ( plugin: builtins.map (file: { - name = "${vault.target}/.obsidian/plugins/${getManifestId plugin}/${file}"; + name = "${vault.target}/.obsidian/plugins/${getManifest plugin.pkg}/${file}"; value = { - source = "${plugin}/${file}"; + source = "${plugin.pkg}/${file}"; }; - }) (readDir plugin) + }) (readDir plugin.pkg) + ) vault.settings.plugins + ++ builtins.map ( + plugin: + builtins.map (file: { + name = "${vault.target}/.obsidian/plugins/${getManifest plugin.pkg}/${file.target}"; + value = if file ? source then { source = file.source; } else { text = file.text; }; + }) (builtins.attrValues plugin.extraFiles) ) vault.settings.plugins; + mkCssSnippets = vault: builtins.map (snippet: { - name = "${vault.target}/.obsidian/snippets/${builtins.baseNameOf snippet}"; - value = { - source = snippet; - }; - }) vault.settings.cssSnippets; - mkTheme = + name = "${vault.target}/.obsidian/snippets/${snippet.name}.css"; + value = if snippet ? source then { source = snippet.source; } else { text = snippet.text; }; + }) (builtins.attrValues vault.settings.cssSnippets); + + mkThemes = vault: - lib.attrsets.optionalAttrs (vault.settings.theme != null) { - name = "${vault.target}/.obsidian/themes/${getManifestId vault.settings.theme}"; + builtins.map (theme: { + name = "${vault.target}/.obsidian/themes/${getManifest theme.pkg}"; value = { - source = vault.settings.theme; + source = theme.pkg; }; - }; + }) vault.settings.themes; in builtins.listToAttrs ( lib.lists.flatten ( @@ -286,7 +401,7 @@ in (mkCorePlugins vault) (mkCommunityPlugins vault) (mkCssSnippets vault) - (mkTheme vault) + (mkThemes vault) ]) vaults ) ); diff --git a/hosts/common/user/configs/gui/obsidian/snippets/editor-monospace.css b/hosts/common/user/configs/gui/obsidian/snippets/editor-monospace.css deleted file mode 100644 index 7dc33a8..0000000 --- a/hosts/common/user/configs/gui/obsidian/snippets/editor-monospace.css +++ /dev/null @@ -1,3 +0,0 @@ -.markdown-source-view.mod-cm6 .cm-scroller { - font-family: var(--font-monospace); -} diff --git a/hosts/common/user/configs/options.nix b/hosts/common/user/configs/options.nix index f8121d0..b2582a1 100644 --- a/hosts/common/user/configs/options.nix +++ b/hosts/common/user/configs/options.nix @@ -5,14 +5,16 @@ let with types; { config, ... }: { - options.email = mkOption { - type = nullOr str; - description = "Email address of the user."; - }; + options = { + email = mkOption { + type = nullOr str; + description = "Email address of the user."; + }; - options.fullName = mkOption { - type = nullOr str; - description = "Full name of the user."; + fullName = mkOption { + type = nullOr str; + description = "Full name of the user."; + }; }; }; in