Hacker News new | past | comments | ask | show | jobs | submit login
Straight.el: next-gen, purely functional package manager for the Emacs hacker (github.com/radian-software)
117 points by bjourne on June 22, 2022 | hide | past | favorite | 40 comments



I use this in combination with `use-package`.

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!


> 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.


Nowadays not too much. For a while flymake languished while flycheck got faster, more, robust, added languages, etc. Probably just a function of when op started using Emacs


Note that "for a while" is in Emacs-time, so we're talking ~2013 to ~2019, i.e. longer than some entire popular editors, that flycheck was the normal way for someone using non-prerelease-Emacs.

(And even now I think I'd stick with flycheck if it weren't also for eglot using flymake by default.)


I have been using straight for a while now and I think it is great! The ability to lazy load everything by default does a lot to make Emacs snappier (or at the very least, faster to boot). Being able to pull packages directly from git (be it local or a forge) makes package development a lot easier. raxod has a lot of really sleek, modern emacs packages that I would encourage everyone to check out, selectrum[0] and ctrf[1] in particular are really great as well.

[0] https://github.com/radian-software/selectrum

[1] https://github.com/radian-software/ctrlf


I moved to straight.el several years ago when I was working on making my Emacs config more repeatable. It’s been simply the best tool for Emacs dependency management. Several packages that I now drive daily I found before they were on MELPA/ELPA; with straight, it was trivial to configure it to clone and install them just with a URL to clone. I’ve also had many bleeding edge updates break stuff for me; I just cd’d into the corresponding elisp directory, git checkout’d the version I wanted, then let straight rebuild the byte compiled files for me automatically on next launch. So. Nice.


Doom emacs[1] also uses straight.el and has been a pleasure to use for the most part.

[1]: https://github.com/doomemacs/doomemacs


Another approach to the problem would be to install Emacs packages with GNU Guix[1].

[1] https://guix.gnu.org/manual/en/html_node/Application-Setup.h...


On top of that, one can use Guix from the comfort of Emacs:

  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.


Would be worth doing a tutorial for r/emacs or #emacs as I'm not sure a lot of people are aware of this.


Yet another option is to use a configuration management system like Ansible.


I think Ansible is a little bit of an overkill for this purpose, but also, it's fundamentally a non-reproducible system-configuration-management tool, just like Emacs' built-in use-package system.

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.


Thanks to straight, setting up emacs on a new machine is as easy as git cloning my config into .emacs.d and launching emacs.


what about LSP servers?


Depends on the LSP client you're using. Eglot doesn't do a whole lot to manage them, and leaves it to the user to install language servers they need. lsp-mode will find and install language servers if needed.


I'm not currently using LSP for any of my work, so this isn't an issue for me.

(Should I be? I mostly write R code, and ESS is fine for that.)


Most often lsp-servers installation is bundled with lsp-mode via 'install-lsp-server'


After stumbling upon straight via Doom Emacs, I finally felt confident enough to built my own, from-scratch configuration, without worrying about the kind of constant issues my colleagues were experiencing on their Doom or Spacemacs setups every few months or sometimes every few weeks.

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 wonder what this adds over the default Emacs package manager?

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.


Can someone smarter than me explain what it means to be a “purely functional” package manager?

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.


Think of side-effects on the system user level instead of the hardware level. A functional package manager doesn't rely on, for example, globally installed libraries. It also installs packages in such a way as to not affect the operation of your system. Nix, for example, keeps everything in a private directory. If you have packages A depending on packages X, Y, and B depending on Y, Z, then A, B, X, Y, and Z will all be placed in separate directories in /nix/store. This can all be done without touching any system or user (or emacs) profiles. Hence, "no side-effects".

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.


It's a bit like nix but only for emacs. Modes are downloaded/built locally and versions pinned. From there you can put in version control your pin file and update/revert updates safely. It also guarantees you get the exact same setup across machines.

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.


My interpretation is that the same initialization config will lead to the same setup every time, in the sense that each installation is pure in a way. Of course, while it probably just works, it's only actually pure if you pin every package to a version.


This is the only way I have managed to have sane package dependencies in my Emacs configuration.


Just from looking at the heading: There is GNU Guix, which also already packages many Emacs packages and many of the contributors / authors of GNU Guix use Emacs to work on it themselves. I have a mostly Guix installed Emacs setup, only including my own init.el and some packages installed through `M-x list-pack RET`, which are not on Guix already. It works quite well and is easy to update.


The problem is that Guix only works on GNU/Linux not even other Unixes as Nix does. Let alone MS Windows.

straight.el works on all of these.


I'm not _aware_ of having any problem that this solves, so I'm probably a horribly inadequate Emacs user. But this repo and some of the author's other work makes it clear he's extremely smart and tasteful so this is probably worth checking out.


The reason I use it is because it checks the git repo of the package out so I can jump in and edit it and be inside a git repo if I wanted to open a PR with my change. When you use package.el it will download .tar's and not have git history inside it.

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.


When updating packages from doom-emacs, it figured out many master -> main transitions (semi-)automatically. I don't know whether that was straight alone or doom emacs, though.


that's not doom for sure, because I'm also getting those branch rename prompts on my from-scratch straight.el based config too.

it could be the built-in vc.el too, because I can imagine straight depending on that, but I haven't checked.


Okay, I do indeed have a bunch of cloned and orphaned stuff where I've needed to do customisations so that makes sense.


I personally use this, I love how it lets you "try out" a package


Looking at the documentation, straight.el took a lot of dedicated work, thanks a lot! Will definitely give it a spin later, which should be rather easy thanks to use-package integration.


+1 After reading through the documentation, I wanted to make the same comment.

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.


I wish there was something like Nix for configuring Emacs.


You can manage your Emacs packages with home-manager, it looks like this:

  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";
    };

  };


Guix works as a package manager for Emacs, though you’ll always need to maintain your init.el

straight.el works too of course but ultimately Emacs configuration is not declarative.


use-package is sort of declarative for many things.


There is also nix-straight, which is used in nix-doom-emacs, although it is fairly limited and takes ages to build when you make any changes.


As I understand it, that's basically what this is.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: