Arroyo developed out of a system originally designed to assemble an
Emacs init.el
, and now it has some
super-powers. The Arroyo Emacs configuration is pretty opinionated as
it's a system designed to work around Evil
Mode and EXWM.
Arroyo Emacs configuration is designed to work closely with the Arroyo Home Manager generator, nearly all system dependencies are installed through Home Manager, and certain submodules may require the use of Home Manager. No Arroyo Emacs features should require running NixOS though, and I'd like to maintain that as much as possible since getting Nix running everywhere is much more feasible than running NixOS everywhere.
Users of the Arroyo Home Manager generator will have access to features available in nix-community/emacs-overlay like:
- the
native-compile
feature - Native GTK with Wayland support (though Wayland is not supported by impotant parts of Arroyo like the EXWM system)
- When using
use-package
, packages will be downloaded and (natively!) compiled in the deploy phase rather than on Emacs startup
Arroyo System Cache Emacs table
require 'arroyo-utils)
(
"~/arroyo-nix/files/init.el")
(defcustom arroyo-emacs-init-location (expand-file-name "Where `arroyo-emacs-generate-init' writes the amalgamated init file."
'arroyo
:group :type 'string)
dolist (kw '("ARROYO_EMACS_MODULE" "ARROYO_EMACS_TANGLED"))
('arroyo-db-keywords kw nil #'equal))
(add-to-list
'arroyo-db--schemata
(add-to-list
'(emacs
[(file :not-null)
(tangled :not-null) (module :not-null)]))
defun arroyo-emacs-update-db (&optional keywords-too)
("P")
(interactive when keywords-too
(
(arroyo-db-update-all-roam-files))if (org-roam-file-p)
(= file $s1)]
(arroyo-db-query [:delete :from emacs :where (
(buffer-file-name))
(arroyo-db-query [:delete :from emacs]))
(when-let* ((module-argsif (org-roam-file-p)
(list [:select [file "" value] :from keywords
(= keyword $s1) :and (= file $s2)]
:where ("ARROYO_EMACS_MODULE"
(buffer-file-name))list [:select [file "" value] :from keywords
(= keyword $s1)]
:where ("ARROYO_EMACS_MODULE")))
apply #'arroyo-db-query module-args)))
(modules (
(arroyo-db-query [:insert :into emacs :values $v1]
(-map (pcase-lambda (`(,file ,_ ,module))vector file (arroyo-emacs--figure-tangled-location file) module))
(
modules))))
defun arroyo-emacs--figure-tangled-location (file-path)
(
(->> file-path
(arroyo-db-query [:select value :from keywords= file $s1)
:where (= keyword "ARROYO_EMACS_MODULE")])
:and (caar)
(format "%s/cce/%s.el" org-roam-directory)))
(
'arroyo-db-update-functions #'arroyo-emacs-update-db) (add-to-list
Arroyo
Emacs init.el
generator
arroyo-emacs-generate-init
can be
called interactively1 to assemble an init.el
file which will have the dependencies
ordered in such a way as to allow the user to user Emacs.
defun arroyo-emacs-generate-init ()
("Write an emacs `init.el' to `arroyo-emacs-init-location' using
tangled files spread throughout an org-roam wiki."
(interactive)
(arroyo-emacs-update-db)let ((dest arroyo-emacs-init-location)
(
(files (arroyo-emacs--ordered-files)))
(with-current-buffer (find-file-noselect dest)
(erase-buffer)dolist (file files)
(
(insert-file-contents file)
(goto-char (point-max)))
(save-buffer))))
defun arroyo-emacs--module-pair-for-rel-file (unordered rel-file)
(second (-find (lambda (elt)
(equal (expand-file-name rel-file org-roam-directory)
(car elt)))
(
unordered)))
defun arroyo-emacs--ordered-files () ;; (ref:ordered-files)
(let* ((unordered (arroyo-db-query [:select [file tangled] :from emacs])) ;; (ref:unordered)
(#'car unordered)) ;; (ref:unordered-filenames)
(unordered-filenames (-map ;; (ref:order-modules)
(order (arroyo-utils-order-modules unordered-filenames)) #'arroyo-emacs--module-pair-for-rel-file unordered))
(partialfn (apply-partially
(ordered (-map partialfn order)))
(->>
ordered#'identity)
(-filter (-uniq))))
This (ordered-files) function is a little bit dense to read, so let's take this apart let-binding by let-binding:
- (unordered) takes the modules out of the Arroyo System Cache as pairs of [file tangled-file location] and then (ref:unordered-filenames) extracts the first filename from the unordered pairs.
- (ref:order-modules) orders
the unordered file-names based on a database-backed topological sort
implemented in Arroyo
Dependency Sorting in
arroyo-utils
. - (module-pair-for-rel-file) is a function designed to find a result-pair from the list of (unordered) which matches the file-name in the newly-reordered fashion. I'm sure there's a better way to do this than with a map+find operation, I failed the technical interview.
In total, this takes the unordered dataset and returns them with a topological sort applied to them, the edges of the topology are pulled from the Arroyo Dependency Sorting cache.
The interactive function is more or less as it says on the tin – it
writes the init.el
to a local directory
for the arroyo-flood.
Arroyo Home Manager support for Emacs
This Nix home-manager import installs Emacs with my generated init.el
file included, packages installed, and
custom overrides included. The versions come out of my Nix Version Pins.
The Emacs package uses, currently 28.0.90 which supports native
compilation – the so-called GccEmacs
and the packages from the init.el
,
natively compiled and ready to go. This is overlayed in to nixpkgs using Arroyo Nix Support
{ pkgs, lib ? pkgs.lib, ... }:
let
versions = import ../versions.nix {};
in pkgs.emacsWithPackagesFromUsePackage {
package = pkgs.emacs-unstable;
# package = pkgs.emacsGit.override {#
# treeSitterPlugins = with pkgs.tree-sitter-grammars; [
# tree-sitter-eex
# tree-sitter-elisp
# tree-sitter-elixir
# tree-sitter-fennel
# tree-sitter-haskell
# tree-sitter-html
# tree-sitter-lua
# tree-sitter-markdown
# tree-sitter-nix
# tree-sitter-scheme
# tree-sitter-sql
# # builtins, mostly
# tree-sitter-bash
# tree-sitter-c
# tree-sitter-cmake
# tree-sitter-cpp
# tree-sitter-css
# tree-sitter-dockerfile
# tree-sitter-go
# tree-sitter-gomod
# tree-sitter-java
# tree-sitter-javascript
# tree-sitter-json
# tree-sitter-python
# tree-sitter-ruby
# tree-sitter-rust
# tree-sitter-toml
# tree-sitter-yaml
# ];
# };
config = <<arroyo-emacs-init-location()>>;
alwaysEnsure = true;
override = epkgs: epkgs // rec {
generate_epkg_overrides()>>
<<};
extraEmacsPackages = epkgs: [
epkgs.consult-org-roam];
}
let emacsOverlay = (import ../versions.nix {}).emacsOverlay null;
in {
nixpkgs.overlays = [
(import emacsOverlay)
];
}
{ config, pkgs, lib, ...}:
let
myEmacs = pkgs.myEmacs; # loads via overlay
emacspeak = pkgs.emacsPackages.emacspeak.override { emacs = myEmacs; };
in
{
home.file.".emacs.d/init.el".source = <<arroyo-emacs-init-location()>>;
programs.info.enable = true;
services.emacs = {
enable = false;
package = myEmacs;
};
programs.emacs = {
enable = true;
package = myEmacs;
};
home.packages = [
emacspeak];
}
Enable ccache for emacsGcc
builds in My NixOS configuration
,#+ARROYONIXOSMODULE: nixos/ccache.nix
{ ... }:
{
programs.ccache = {
packageNames = ["emacs-unstable"];
};
nix.extraOptions = ''
extra-sandbox-paths = /nix/var/cache/ccache
'';
}
NEXT fix ccache support
DONE reenable ccache
https://github.com/NixOS/nixpkgs/pull/137936
Literate Programming helpers
I want to be able to construct a home-manager import dynamically which can
be used to install with emacs-overlay
functionality. I also want it to be able to inject arbitrary packageOverrides
in to it via references in
stored in documents' ARROYO_HOME_EPKGS
property keyword.
defun arroyo-emacs-epkgs ()
(
(->> (arroyo-db-query [:select [file value] :from keywords= keyword "ARROYO_HOME_EPKGS")])
:where (#'second)
(-map lambda (path)
(-map (let ((path (expand-file-name path "~/arroyo-nix")))
(
(with-current-buffer (find-file-noselect path)let ((bs (buffer-string)))
(
(kill-this-buffer)
bs)))))"\n")))
(s-join 'arroyo-db-keywords "ARROYO_HOME_EPKGS" nil #'equal) (add-to-list
arroyo-emacs-epkgs
can be used to
insert any overridden elisp package in to the registry for use-package
to install, including things with
patches or personal forks. yummy. apply a ARROYO_HOME_EPKGS
keyword to the page
to include it here.
(arroyo-emacs-epkgs)
arroyo-emacs-init-location
above is
simply the Arroyo Emacs-managed init.el
:
; arroyo-emacs-init-location
"<arroyo/files/init.el>"
NEXT how to automate epkg tangling, etc.
can use org-roam's Arcology.Roam.File to know whether a file has been updated and tangle it as part of the dynamic-home-manager dynamic-nixops etc… those things will check a cache to see if the files have changed, and tangle them and then this file if so?
DONE need a reverse of ARROYO_MODULE_WANTS
for specifying
"wanted-by"s
Footnotes
provide 'arroyo-emacs) (
that is, by pressing
Alt-x
/M-x
and then typing the name of the command; Modern Interface Terms↩︎