about summary refs log tree commit diff
path: root/overlays/patches/emacs/overlay/elisp.nix
diff options
context:
space:
mode:
Diffstat (limited to 'overlays/patches/emacs/overlay/elisp.nix')
-rw-r--r--overlays/patches/emacs/overlay/elisp.nix102
1 files changed, 102 insertions, 0 deletions
diff --git a/overlays/patches/emacs/overlay/elisp.nix b/overlays/patches/emacs/overlay/elisp.nix
new file mode 100644
index 000000000000..aff0b484023a
--- /dev/null
+++ b/overlays/patches/emacs/overlay/elisp.nix
@@ -0,0 +1,102 @@
+/*
+Parse an emacs lisp configuration file to derive packages from
+use-package declarations.
+*/
+
+{ pkgs }:
+let
+  parse = pkgs.callPackage ./parse.nix { };
+  inherit (pkgs) lib;
+
+
+
+in
+{ config
+# bool to use the value of config or a derivation whose name is default.el
+, defaultInitFile ? false
+# emulate `use-package-always-ensure` behavior (defaulting to false)
+, alwaysEnsure ? null
+# emulate `#+PROPERTY: header-args:emacs-lisp :tangle yes`
+, alwaysTangle ? false
+, extraEmacsPackages ? epkgs: [ ]
+, package ? pkgs.emacs
+, override ? (self: super: { })
+}:
+let
+  ensureNotice = ''
+    Emacs-overlay API breakage notice:
+
+    Previously emacsWithPackagesFromUsePackage always added every use-package definition to the closure.
+    Now we will only add packages with `:ensure`, `:ensure t` or `:ensure <package name>`.
+
+    You can get back the old behaviour by passing `alwaysEnsure = true`.
+    For a more in-depth usage example see https://github.com/nix-community/emacs-overlay#extra-library-functionality
+  '';
+  doEnsure = if (alwaysEnsure == null) then builtins.trace ensureNotice false else alwaysEnsure;
+
+  isOrgModeFile =
+    let
+      ext = lib.last (builtins.split "\\." (builtins.toString config));
+      type = builtins.typeOf config;
+    in
+      type == "path" && ext == "org";
+
+  configText =
+    let
+      type = builtins.typeOf config;
+    in # configText can be sourced from either:
+      # - A string with context { config = "${hello}/config.el"; }
+      if type == "string" && builtins.hasContext config && lib.hasPrefix builtins.storeDir config then builtins.readFile config
+      # - A config literal { config = "(use-package foo)"; }
+      else if type == "string" then config
+      # - A config path { config = ./config.el; }
+      else if type == "path" then builtins.readFile config
+      # - A derivation { config = pkgs.writeText "config.el" "(use-package foo)"; }
+      else if lib.isDerivation config then builtins.readFile "${config}"
+      else throw "Unsupported type for config: \"${type}\"";
+
+  packages = parse.parsePackagesFromUsePackage {
+    inherit configText isOrgModeFile alwaysTangle;
+    alwaysEnsure = doEnsure;
+  };
+  emacsPackages = (pkgs.emacsPackagesFor package).overrideScope' (self: super:
+    # for backward compatibility: override was a function with one parameter
+    if builtins.isFunction (override super)
+    then override self super
+    else override super
+  );
+  emacsWithPackages = emacsPackages.emacsWithPackages;
+  mkPackageError = name:
+    let
+      errorFun = if (alwaysEnsure != null && alwaysEnsure) then builtins.trace else throw;
+    in
+    errorFun "Emacs package ${name}, declared wanted with use-package, not found." null;
+in
+emacsWithPackages (epkgs:
+  let
+    usePkgs = map (name: epkgs.${name} or (mkPackageError name)) packages;
+    extraPkgs = extraEmacsPackages epkgs;
+    defaultInitFilePkg =
+      if !((builtins.isBool defaultInitFile) || (lib.isDerivation defaultInitFile))
+      then throw "defaultInitFile must be bool or derivation"
+      else
+        if defaultInitFile == false
+        then null
+        else
+          let
+            # name of the default init file must be default.el according to elisp manual
+            defaultInitFileName = "default.el";
+          in
+          epkgs.trivialBuild {
+            pname = "default-init-file";
+            src =
+              if defaultInitFile == true
+              then pkgs.writeText defaultInitFileName configText
+              else
+                if defaultInitFile.name == defaultInitFileName
+                then defaultInitFile
+                else throw "name of defaultInitFile must be ${defaultInitFileName}";
+            packageRequires = usePkgs;
+          };
+  in
+  usePkgs ++ extraPkgs ++ [ defaultInitFilePkg ])