diff --git a/README.org b/README.org index ee0bb295a..d77482dbb 100644 --- a/README.org +++ b/README.org @@ -14,6 +14,32 @@ is updated daily. This package is named =emacsGit= in the overlay. +** Extra library functionality +This overlay comes with an extra function to generate an Emacs closure from =use-package= declarations. +This is an abstraction on top of =emacsWithPackages=. +#+BEGIN_SRC nix +{ + environment.systemPackages = [ + (emacsWithPackagesUsePackage { + config = builtins.readFile ./emacs.el; + # Package is optional, defaults to pkgs.emacs + package = pkgs.emacsGit; + # Optionally provide extra packages not in the configuration file + extraEmacsPackages = epkgs: [ + epkgs.cask + ]; + # Optionally override derivations + override = epkgs: epkgs // { + weechat = epkgs.melpaPackages.weechat.overrideAttrs(old: { + patches = [ ./weechat-el.patch ]; + }); + }; + }) + ]; +} +#+END_SRC + + ** Usage of the overlay *** Latest master each rebuild One way, and probably the most convenient way to pull in this overlay is by @@ -28,11 +54,13 @@ package =emacsGit= available. These of course change quite rapidly and will cause compilation time. #+BEGIN_SRC nix +{ nixpkgs.overlays = [ (import (builtins.fetchTarball { url = https://github.com/nix-community/emacs-overlay/archive/master.tar.gz; })) ]; +} #+END_SRC # LocalWords: EXWM NixOS emacsGit diff --git a/default.nix b/default.nix index 23901b11c..d7d167a5e 100644 --- a/default.nix +++ b/default.nix @@ -37,6 +37,8 @@ in { ]; }); + emacsWithPackagesFromUsePackage = import ./elisp.nix { pkgs = self; }; + emacsPackagesNgFor = emacs: ( (super.emacsPackagesNgFor emacs).overrideScope'(eself: esuper: let diff --git a/elisp.nix b/elisp.nix new file mode 100644 index 000000000..aff72b7dc --- /dev/null +++ b/elisp.nix @@ -0,0 +1,44 @@ +/* +Parse an emacs lisp configuration file to derive packages from +use-package declarations. +*/ + +{ pkgs }: + +let + isStrEmpty = s: (builtins.replaceStrings [" "] [""] s) == ""; + + splitString = _sep: _s: builtins.filter + (x: builtins.typeOf x == "string") + (builtins.split _sep _s); + + stripComments = dotEmacs: let + lines = splitString "\n" dotEmacs; + stripped = builtins.map (l: + builtins.elemAt (splitString ";;" l) 0) lines; + in builtins.concatStringsSep " " stripped; + + parsePackages = dotEmacs: let + strippedComments = stripComments dotEmacs; + tokens = builtins.filter (t: !(isStrEmpty t)) (builtins.map + (t: if builtins.typeOf t == "list" then builtins.elemAt t 0 else t) + (builtins.split "([\(\)])" strippedComments)); + matches = builtins.map (t: + builtins.match "^use-package[[:space:]]+([A-Za-z0-9_-]+).*" t) tokens; + in builtins.map (m: builtins.elemAt m 0) + (builtins.filter (m: m != null) matches); + +in { + config, + extraEmacsPackages ? epkgs: [], + package ? pkgs.emacs, + override ? (epkgs: epkgs) +}: let + packages = parsePackages config; + emacsPackages = pkgs.emacsPackagesNgGen package; + emacsWithPackages = emacsPackages.emacsWithPackages; +in emacsWithPackages (epkgs: let + overriden = override epkgs; + usePkgs = builtins.map (name: overriden.${name}) packages; + extraPkgs = extraEmacsPackages overriden; +in [ overriden.use-package ] ++ usePkgs ++ extraPkgs)