Straight.el: next-gen, purely functional package manager for the Emacs hacker
github.com
github.com
Here's the relevant section copied from my config, copied from right at the top:
;; Straight bootstrap
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
(bootstrap-version 5))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
;; Set up use-package for tidier package configuration/installation
(straight-use-package 'use-package)
(setq straight-use-package-by-default t)
;; Add diminish, which makes it easier to customize lighters (minor mode display)
(use-package diminish)
I use it since it allows for transparent installations, meaning you can find the straight folder (in my case "~/.config/emacs/straight/repos/") and see git repos for all of your installed packages. From there you can edit them, commit to upstream, pull, all of the usual stuff.Another main reason to use it is that it allows for repeatable installations, something I had struggled with previously with `package.el`. Run `M-x straight-freeze-versions`, and you have a lock file made with the exact commits of all of the dependencies you're running. That way, you don't need to push your entire emacs config folder up to your dotfiles repo, and can get a new install of emacs set up feature-(and bug)-exact on new machines easily.
One gripe I have about it though is that flycheck no longer recognizes `use-package` syntax in my init file and throws a bunch of warnings as a result. If anyone knows a quick fix, please let me know!
I don't use `use-package` (or `flycheck`, what advantage does it have over the built in `flymake`?), but I suspect adding `(require 'use-package)` after `(straight-use-package 'use-package)` would fix it.
(And even now I think I'd stick with flycheck if it weren't also for eglot using flymake by default.)
[1] https://guix.gnu.org/manual/en/html_node/Application-Setup.h...
Straight.el carries over the idea of reproducible builds from the Nix package manager and applies it to the specifics of the Emacs ecosystem.
So the whole point is to get away from the reproducibility issues of Ansible, use-package and the likes.
guix install emacs-guix
The Emacs interface includes Magit-style popup menus, lets you install/remove/upgrade/browse packages, roll back, edit package definitions, navigate system services, and more.(Should I be? I mostly write R code, and ESS is fine for that.)
I knew very little about Emacs (27.1) at that time, yet it was an effortless endeavor to grow my own config: https://github.com/onetom/onetomacs
I had literally zero hiccups with packages, though I haven't even froze them, while kept upgrading every few weeks with straight-pull-all.
I think the other big contributor to my pleasant experience was that I've vetted and studied every package, before I've added it to my config and tried to figure out what would it offer compared to built-in functionality.
I'm programming for 40 years by now and primarily in Clojure for the past ~7 years (using IntelliJ/Cursive), so I guess that helped a lot too...
I have this in my init.el:
(custom-set-variables
...
'(package-selected-packages
'(package1 package2 ...))
...)
;;; Bootstrap pkgs
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t)
(package-initialize)
(unless package-archive-contents
(package-refresh-contents))
(package-install-selected-packages)
Then for all mode-specific configuration, I have something like: (eval-after-load 'XXX-mode
'(progn
(setq XXX 'something)
(define-key XXX-mode (kbd "C-c .") 'do-something)))
Has been working well enough for me as a config I can share between installations.Because it’s confusing to use the term this way. In programming “purely functional” means no side effects; writing files to disk and mutating the state of the host system is a strong set of side effects.
Paired with use-package it makes emacs configs very compact, typically you can have a single conf file + the versions file for everything related to ones setup. That makes it very easy to transport.
Even if you use nix/guix it's more convenient imho to use straight.el for emacs, as it's standalone as long as emacs is available.
Of course, you probably want some side-effects, so you'll put symlinks to the stuff you want in your user profile, or into a .envrc file in the root of a project.
straight.el works on all of these.
Edit: Also because of above, straight makes it easy to check out specific branches - this isn't easy using package.el - your packages are pinned to a version - whereas this makes it super easy to just checkout a branch someone made without waiting for a new release.
it could be the built-in vc.el too, because I can imagine straight depending on that, but I haven't checked.
10 or 20 years ago (I have been using Emacs for about 40 years) I was really happy with my Emacs setup but now I have support for so many languages that my current setup seems like a mess. I will try Straight.el.
straight.el works too of course but ultimately Emacs configuration is not declarative.
programs.emacs = {
enable = true;
extraPackages = epkgs: with epkgs; [
ace-jump-mode
ag
auto-indent-mode
browse-kill-ring
];
};
and here a function that builds a package that is missing in MELPA: build_movelines = epkgs: epkgs.trivialBuild {
pname = "move-lines";
version = "2.0";
src = pkgs.fetchFromGitHub {
owner = "targzeta";
repo = "move-lines";
rev = "master";
sha256 = "0pbvn11n9sw3mg3hpcpc8p80zh53sxyjbhqqxdwbwg8dwpc7r5ij";
};
};