zainab-ali / emacs-nix

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

What’s inside

This repository contains a Nix derivation of Emacs. It does not depend on NixOS (so can be used with the Nix package manager) and is platform independent.

The code contained in this repository is licensed under GNU General Public License.

Its goal is a reproducible build of an emacs binary that includes all of its Elisp packages. A standard Emacs setup (i.e. without Nix) would download extra Elisp packages from Melpa on startup.

For example, consider the following statement in an init.el:

(use-package magit)

This would download the .el files of the magit package into the ~~/.emacs.d/melpa~ directory. These would be obtained from the HEAD of the magit git repository.

In contrast, this project downloads magit when the emacs binary is built. Nothing is downloaded when emacs is run.

In addition, the version of magit is not the HEAD, but a fixed commit hash.

Mechanism

This Emacs Nix setup is a little unconventional. Before going into details, let’s first explore the standard setup documented in the NixOS manual.

This shows how to write a nix derivation for emacs that includes packages from melpa. Note that there is no elisp code ⸺ each package is itself a nix derivation containing .el files.

While this approach is a working solution, it isn’t as easy to use and configure as use-package. Instead, this repository uses the Emacs overlay to get the best of both worlds by writing use-package expressions in .el files and parsing these into nix derivations.

The expression (use-package magit) in the melpa-mirror-packages.el file is parsed into a magit nix derivation. This outputs .el files that are ultimately placed in the site-lisp directory.

Extra .el files (ones that aren’t packaged in MELPA) are obtained from their git repositories by using the build-emacs-package function. These are byte compiled at build time to produce faster .elc files.

Quickstart

Download

Run the following command on every time this code is modified.

nix-env -i -f default.nix

Troubleshooting

Run the nix repl

M-x nix-repl

Import the expression (function) from defalt.nix.

func = import ./default.nix

Call the function.

result = func {}

This produces a lazy set.

Build the derivation to evaluate the set.

:b result

This should produce an output

this derivation produced the following outputs:
  out -> /nix/store/l20amhsjrhni6kaqi8w515nv7x2xcryc-emacs-site-lisp

The structure of which is:

> tree -L 4 /nix/store/ghqamfzd5s95k1fm4ynjwhpnr70m1wbm-emacs-site-lisp/
/nix/store/ghqamfzd5s95k1fm4ynjwhpnr70m1wbm-emacs-site-lisp/
├── bin
│   ├── ctags -> /nix/store/r7wlhbhqpk1ixbnddnj2xwhmiy10rl7i-emacs-with-packages-27.2/bin/ctags
│   ├── ebrowse -> /nix/store/r7wlhbhqpk1ixbnddnj2xwhmiy10rl7i-emacs-with-packages-27.2/bin/ebrowse
│   ├── emacs -> /nix/store/r7wlhbhqpk1ixbnddnj2xwhmiy10rl7i-emacs-with-packages-27.2/bin/emacs
│   ├── emacs-27.2 -> /nix/store/r7wlhbhqpk1ixbnddnj2xwhmiy10rl7i-emacs-with-packages-27.2/bin/emacs-27.2
│   ├── emacsclient -> /nix/store/r7wlhbhqpk1ixbnddnj2xwhmiy10rl7i-emacs-with-packages-27.2/bin/emacsclient
│   └── etags -> /nix/store/r7wlhbhqpk1ixbnddnj2xwhmiy10rl7i-emacs-with-packages-27.2/bin/etags
└── share
    ├── applications -> /nix/store/zvpy3f4bhav21c9r7nf1ifp38j3i2j31-emacs-27.2/share/applications
    ├── emacs
    │   └── site-lisp
    │       ├── browse-repositories
    │       ├── cartography.el -> /nix/store/732l3jvnfimkg4cy6ak288g8xwkpbnys-emacs-site/share/emacs/site-lisp/cartography.el
    │       ├── coe
    │       ├── dashboard.el -> /nix/store/732l3jvnfimkg4cy6ak288g8xwkpbnys-emacs-site/share/emacs/site-lisp/dashboard.el
    │       ├── fandango
    │       ├── light.el -> /nix/store/732l3jvnfimkg4cy6ak288g8xwkpbnys-emacs-site/share/emacs/site-lisp/light.el
    │       ├── melpa-mirror-packages.el -> /nix/store/732l3jvnfimkg4cy6ak288g8xwkpbnys-emacs-site/share/emacs/site-lisp/melpa-mirror-packages.el
    │       ├── melpa-mirror-packages.elc -> /nix/store/732l3jvnfimkg4cy6ak288g8xwkpbnys-emacs-site/share/emacs/site-lisp/melpa-mirror-packages.elc
    │       ├── mill.el -> /nix/store/732l3jvnfimkg4cy6ak288g8xwkpbnys-emacs-site/share/emacs/site-lisp/mill.el
    │       ├── pollen-mode
    │       ├── project+.el -> /nix/store/732l3jvnfimkg4cy6ak288g8xwkpbnys-emacs-site/share/emacs/site-lisp/project+.el
    │       ├── project+.elc -> /nix/store/732l3jvnfimkg4cy6ak288g8xwkpbnys-emacs-site/share/emacs/site-lisp/project+.elc
    │       ├── site-packages.el -> /nix/store/732l3jvnfimkg4cy6ak288g8xwkpbnys-emacs-site/share/emacs/site-lisp/site-packages.el
    │       └── subed
    ├── icons -> /nix/store/zvpy3f4bhav21c9r7nf1ifp38j3i2j31-emacs-27.2/share/icons
    ├── info -> /nix/store/zvpy3f4bhav21c9r7nf1ifp38j3i2j31-emacs-27.2/share/info
    └── man -> /nix/store/zvpy3f4bhav21c9r7nf1ifp38j3i2j31-emacs-27.2/share/man

Initialize

The site-init.el and site-packages.el are bootstrap mechanisms because the emacs created by nix looks for anything under share/site/elisp in NIX_PROFILES. We make use of that fact to have a minimal init.el.

Add the following to the init.el:

;; -*- lexical-binding: t; -*-

(setq gc-cons-threshold (* 50 1000 1000))
(require 'melpa-mirror-packages)
(require 'site-packages)
(evil-mode)
(setq gc-cons-threshold (* 2 1000 1000))

Update

The Emacs in this repository is tied to a given commit hash of the emacs overlay. This commit is a reference to a point in time for all the repositories in MELPA.

To update Emacs, modify this commit hash and rebuild.

overlays = [
  (import (builtins.fetchGit {
    url = "https://github.com/nix-community/emacs-overlay.git";
    rev = "e3c046d45ce2d9aa07fd54a330f42edc352e12d5";
    ref = "master";
  }))
];

Fonts

This assumes the font configuration

fonts = with pkgs; [
  source-code-pro
  source-sans-pro
  source-serif-pro
  ibm-plex
];

Addendum

Fonts

Fonts cause problems because they need to be installed under specific directories if we are not using NixOS. Font config looks under $HOME/.local/share/fonts for any fonts we might want.

This is slightly unfortunate, but we can still bundle the fonts that we want available using Nix by creating symlinks between the nix store font and the font that we care about.

Installation

See imperative installation of user fonts, NixOs Wiki.

For example, to install FiraCode:

# Download the font
font=$(nix-build --no-out-link '<nixpkgs>' -A fira-code)/share/fonts/truetype/*
# Copy and pase the directory
mkdir ~/.local/share/fonts
cp $font ~/.local/share/fonts
fc-cache
# Verify that the font has been installed
fc-list -v | grep -i fira

About

License:Other


Languages

Language:Emacs Lisp 84.8%Language:Nix 15.2%