Skip to content

A new emacs configuration that's guix.el friendly and hopefully more portable/manageable. From https://github.com/daviwil/dotfiles

Notifications You must be signed in to change notification settings

dcunited001/.emacs.guix

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Emacs Config

Based on the .emacs.d config in the guix-home branch of daviwil/dotfiles. His config allows you to easily combine dependencies pulled from straight or guix.

Considering the guix packages just updated Emacs 29 -> 30 underneath me while I was migrating dotfiles and I only noticed in the `guix pull` output…

… then I think that this system may work out alright.

Note: the Guix manifest for this project – the emacs-g.scm file which should be manifest.scm – probably includes some custom packages only found in my dotfiles channel. As soon as you nix.flake, everone else will too.

Setup

Doom Emacs wasn’t built in a day.

… So expect some snags along the way.

Not a bene: maintaining the profile currently requires (in this order).

  • Run M-x straight-pull-all before closing the emacs server
  • Run gmacs -- -q for a fresh process. Keep the server open for a great good.
  • M-: and run (load (expand-file-name "init.el" dc/emacs-d))
  • Then M-x straight-rebuild-all

Or maybe just delete ~/.emacs.g/straight/repos/straight.el/straight.eln and run M-x straight-rebuild-all after probably one error, followed by straight-rebuild-all. This avoids the need for obarray gymnastics.

Or travel in time and try to fix Doom Emacs environment/dotfiles from configuring Guile scheme incorrectly.

If the Guix profile contains an updated version of Emacs whose *.eln is no longer compatible, you may get weird behavior. I’m not sure what kind of wierd that is, which is exactly the kind of undefined that I’d prefer to avoid. I haven’t had many problems in the past, but keeping ~/.emacs.g/straight does seem to improve performance.

Paths

Assumed file paths are found in ./init.el

Emacs paths & variables

varvaluedescription
dc/emacs-chemacs$HOME/.emacs.d/now you haz backup plan
dc/emacs-d$HOME/.emacs.g/well this is confusing
dc/emacs-cache$HOME/.cache/emacs/
dc/emacs-dw$HOME/.emacs.g/dwadded to load-path
dc/emacs-modules$HOME/.emacs.g/modulesadded to load-path

Org paths & variables

varvaluedescription
org-directory$ORG_DIRECTORY
org-roam-directory$ORG_DIRECTORY/roam/
org-roam-db-locationmay exhibit problems with syncthing

Other files

varvaluedescription

For a more complete list of .emacs.d file paths, see these lines in emacscollective/no-littering.

Chemacs

migrate away from chemacs2 with -init-directory

Packages

Guix

Dependencies are loaded from guix first by a manifest and straight dependencies are loaded on top.

Update Guix Packages

Update with the script below.

  • If the profile doesn’t exist, setting INSTALL_EMACS will run activate it
  • If debugging is needed, set DEBUG_EMACS and a new guix profile will be activated. Set the variable again when updating to update the debugging profile.
  • Other supporting scripts like a systemd service or launcher scripts need to be updated to respond to DEBUG_EMACS as expected.
  • The repo needs to be cloned to the installation location first. The supporting scripts expect everything to be in ~/.emacs.g
# hmmm +- works, but ensure DEBUG_EMACS is unset
emacs_profile="emacs-g${DEBUG_EMACS+-debug}"
#default_target=".emacs.g${DEBUG_EMACS+.debug}"
default_target=".emacs.g"
target="${INIT_EMACS:-$HOME/$default_target}"

emacs_manifest="emacs-g.scm"
new_manifest="$emacs_profile.scm"
guix_manifests=$HOME/.config/guix/manifests

guix_channel=$HOME/.dotfiles

cp "$target/$emacs_manifest" "$guix_manifests/$new_manifest"
if [ -d "$GUIX_EXTRA/$emacs_profile" ]; then
    update-profiles $emacs_profile
else
    activate-profiles $emacs_profile
fi

Straight

Moving ~/.emacs.g to a new location may require blowing away straight with rm -rf ~/.emacs.g/straight and reloading emacs to reinstall everything.

Instead of doing it like a caveman, you can also run straight-prune-build and straight-rebuild-all from a fresh emacs session. I miss Doom Emacs already.

Fonts

If you want to use the font packages from Guix, you’ll need to ensure that the font directories in ~/.guix-extra-profiles is made available in fontconfig.

no-littering

This package ensures that most of your emacs-generated files like cache, history, etc end up inside ~/.emacs.g/etc or ~/.emacs.g/var

Emacs Config

System Config

Per-System Settings

External Tools

Integrate Pomm with Notifications

This is tangled in my dotfiles configured

if ps -e | grep emacs >> /dev/null; then
    emacsclient --eval "(if (boundp 'pomm-current-mode-line-string) pomm-current-mode-line-string \"\") " | xargs echo -e
fi
[module/pomm]
type = custom/script
exec = /home/pavel/bin/polybar/pomm.sh
interval = 1

Initial Run

Install all-the-icons

This package needs to be loaded by straight in order for the font to be installed properly. When it’s not, dired won’t function.

Run M-x all-the-icons-install-fonts

Emacs Server

Launch emacs with script

export GUIX_SOURCE=$_ECTO/guix/guix
export EMACS_SOURCE=$_ECTO/emacs/emacs/src

# either set DEBUG_EMACS=1 (unset completely to avoid)
# or pass full path with -p
emacs_profile_name="emacs-g${DEBUG_EMACS+-debug}"
emacs_profile=$GUIX_EXTRA/$emacs_profile_name/$emacs_profile_name
search_paths=0

while getopts :Zp OPT; do
    case $OPT in
        Z|+Z)
            search_paths=1
            ;;
        p|+p)
            emacs_profile="$OPTARG"
            ;;
	--)
            break
	    ;;
        *)
            echo "usage: `basename $0` [+-p ARG} [--] ARGS..."
            echo "-p profile/link"
            exit 2
    esac
done
shift `expr $OPTIND - 1`
OPTIND=1

if [ 0 -lt "$search_paths" ]; then
    guix shell -E "^EMAIL$" \
         -E 'EMACS_SOURCE' \
         -E 'GUIX_SOURCE' \
         -p $emacs_profile \
         --search-paths
else
    guix shell -E "^EMAIL$" \
         -E 'EMACS_SOURCE' \
         -E 'GUIX_SOURCE' \
         -p $emacs_profile \
         -- emacs "$@"
fi

Launch emacs client with script. It really needs to be the same profile (it will probably try to connect anyways)

# either set DEBUG_EMACS=1 (unset completely to avoid)
# or pass full path with -p
emacs_profile_name="emacs-g${DEBUG_EMACS+-debug}"
emacs_profile=$GUIX_EXTRA/$emacs_profile_name/$emacs_profile_name
search_paths=0

while getopts :Zp OPT; do
    case $OPT in
        Z|+Z)
            search_paths=1
            ;;
        p|+p)
            emacs_profile="$OPTARG"
            ;;
	--)
	    break
	    ;;
        *)
            echo "usage: `basename $0` [+-p ARG} [--] ARGS..."
            echo "-p profile/link"
            exit 2
    esac
done
shift `expr $OPTIND - 1`
OPTIND=1

guix shell -E "^EMAIL$" \
     -p $emacs_profile \
     -- emacsclient -c "$@"

TODO: Shepherd

Shepherd handles service mgmt, but soon this will be specified in Guix Home. For now, the service is spec’d by scheme in ~/.config/shepherd

TODO: SystemD

XDG Desktop

Guix Home

Debugging Emacs

Running with gdb

GDB expects a raw binary or one with args. That means you can’t just use the gmacs script above, but you need a gdb launcher script. Watch this video in slow-motion for a gdb setup with tmux.

Potential Issues

Problems ensue:

Emacs loaded in 30.39 seconds with 27 garbage collections. [yas] Prepared just-in-time loading of snippets successfully.

And running the profile uses have of my 32 CPU threads. Wow. I’m not even sure… (and the light came on)

Sharing the same .emacs.d directory

There’s at least one big problem here: Can the emacs-g-debug profile run from the same init.el? This depends on how compiling emacs package “link” to their other dependencies. So of course, the answer is ¯\_(ツ)_/¯ or more precisely:

Over here on the x-axis we have … and on the y-axis we have ‘find out.’

I still haven’t really found out yet. I’m pretty sure they link by symbol name, which is why autoload and declare-function do what they do, but I skipped that part of Emacs 202 way back in 2014.

The straight packages will be built from whatever profile loads them. The Guix emacs-* packages handle byte-compiling, whereas straight will build its code on top of the environment it gets, until it’s asked to rebuild everything. These builds are actually isolated from one another or, at least they refer to the outputs of whatever’s in their guix dependency tree – this tree does not depend on emacs, only on the emacs-build-system process, see also Emacs Packages. The Guix profile does some management of the dependency tree for a profile’s set of dependencies.

Sharing the no-littering directory

Yeh… probably don’t check your email if both the emacs-g and emacs-g-debug are active and both think they own all the files.

Notes

TL;DR; for a better teleological overview on workflow why & how for…

org-agenda
see Organize Your Life In Plain Text or Rainer König’s Youtube
org-roam zettelkasten
see Vidianos-Giannitsis/Dotfiles/emacs/.emacs.d/libs/Zettelkasten.org

Org Agenda

Priorities

I have 5 priorities configured.

Capturing

I attempt to capture as close to the context as possible, which is usually the project. I’ve imported some of the Doom Emacs capture templates.

Agenda Files

This will be initially set to dc/org-roam-n-dailies, which defaults to 5. This clears everything out.

From there, the todo.org for projects can be appended.

Refiling

This is initially set as:

(setq-default org-refile-targets `((nil :maxlevel . 3)
      (org-agenda-files :maxlevel . 2)
      (org-default-notes-file :maxlevel . 2))
      org-outline-path-complete-in-steps nil
      org-refile-use-outline-path 'file)

There should be an Inbox in each todo.org file, along with some top-level categories. For agenda files, two levels of headings are available in the completing-read.

Other variants of org-refile commands can be created/used to allow for more control when needed.

Learning Org Agenda

For an overview from an experienced org-agenda user, see Organize Your Life In Plain Text. It’s pretty much the definitive guide on the subject. There are also these videos from Rainer König, which are by far the best videos for explaining the “why” behind using org-agenda’s features in addition to the how. And it’s the why that’s very difficult to figure out on your own without being able to simply immitate someone else’s patterns.

There are features of org-agenda which if you don’t use, then you’re not really using org-agenda – in which case you’re likely generating large volumes of text to manage. Ask any writer or editor: writing is easy, editing takes forever.

That said, org-mode itself is already too large to learn quickly, especially if you’re attempting to use org-babel or other features like that. So you have to focus on categories of features and think a ton about your own process. Org Agenda and Org Roam and are, for now, very personal information management systems. They are much more personal than other similar PIMS.

There’s some magic to using for GTD, which isn’t necessarily obvious.

Typical GTD traps include:

Tagging, scoring, filtering and categorizing
The cyclomatic complexity of tasks

in plain english: the size/scope of your agile “stories” along with the number of subitems in a TODO list. The decisions a project manager makes can have multiplicative effects on how their team interacts with the system.

This is your own system, but how you decide to structure tasks in the future will determine how valuable some features will be or how “stickable” your habits will be. The org-clock features are a good example of something that will be extremely valuable if you can structure your tasks properly. The smaller a parent task, the more limited its time-tracking history.

Org-agenda challenges include:

Learning org-capture templates and engraining them into your workflow.
Learning about target files for org-capture and org-refile.

If you don’t configure this properly, emacs may sputter out when dealing with too many headlines. It will be tough for you to quickly navigate the chaos.

The schema of headlines

This is critical for org-agenda and org-roam.

  • You should approach the design of the schema like a search optimizaton specialist thinks about a site’s map & content or like a webapp developer thinks about desigining a site’s URL’s to be future proof, discoverable and meaningful.
  • You should be designing a relatively future-proof system (at least one that is find-and-replaceable) where you think of both files and headlines as being URL’s.
The cyclomatic complexity of your org-roam and org-agenda source files.

You have files, you have headlines. Your files can have properties, but so can headlines. What’s the difference between an org file and a headline? It’s almost arbitrary. You should not think as though there are clear file-like boundaries between things in your org files: all the files can be thought of as headlines and all headlines can be thought of as files.

Notice how the IEEE refs for web domains, web URLs and the DOM tree basically create a similar space – and you should think of these as not existing in separate spaces, but in separate dimensions of a shared space. In practice, however, it’s impractical and, really, just overstimulating to do so. There are many exceptions. But it’s useful to understand:

Now your problem is a quite a bit more like deciding what URL’s should be on a website and what your tags should be if some small combination of them were to make your content more discoverable (where it markdown) and more functional if it is org. Since org is a PIMS (and since it’s your PIMS), you at least don’t have the “change management” problem. This makes it a good means of experimenting with different systems.

However, the more content you make, the more you’d have to edit – this should be considered whether your are making changes to your system or whether you are not making changes.

finish enumerating the gotchas

On Ontology

Your decisions in maintaining consistency in content synergize with the emacs tools you use to query or interact with the data. This kind of thinking is (or should be) called “ontological thinking” … but that term is a bit ambiguous,

This ambiguity may be why people in the West are so fucked up in the head. The smarter people among them who didn’t make it far enough in philosophy may not properly dillienate the “study of being” from the term’s usage in categorizing the metaphysical into [hopefully] mutually exclusive sets of nameable categories – e.g. the four elements from alchemy. And this is the source of almost every problem in conceptualization or epistemology: trees eventually must become graphs or networks to adequately describe things. When a system of categorization can maintain its partitioned categories, then trees can always neatly branch into completely separate things.

A different schism regarding conceptualization (of a different nature) occurs in Math where one begins to need Category Cheory instead of relying on Set Theory as a comprehensive foundation.

So think back to when people actually browsed the internet, instead of Facebook. People had personal blogs and they typically need two features to help make their content discoverable: categories and features. The categories and subcategories are the tree-like system of mutually exclusive groups mentioned above. The tags feature are a many-to-many system of classifying content to make it more discoverable. But, for the old-school blogger – what should be a category and what should be a tag? It’s unclear. Maybe tags should also be categories? Or maybe you should only use tags. Fortunately, every website implicitly uses a system almost identical to that of sub/categories: the URL/URI. Every branch point in the categories corresponds to a foreslash in the URL.

Problem solved (or sidestepped) – categories are an unnecessary abstraction. The best part? You don’t have to rack your brain on some O(N^N) ontological problem – that’s just a generous estimation on the complexity.

Why

Why Not Doom Emacs?

Doom is a great way to explore features. The codebase is a fantastic showcase of emacs-lisp metaprogramming and Emacs config ideas. I don’t use evil-mode, which isn’t much of a problem in Doom, but it’s still great. Basically it came down to whether Guix is more important to me than Doom Emacs.

In Doom Emacs, mixxing Guix and Straight dependencies is a recipe for serious problems – mostly where native comp encounters duplicate dependencies. See this r/guix post for a description of issues with guile..

But there are benefits to pulling deps from guix:

  • For one, on foreign distro’s, your GUILE_LOAD_PATH will be simple to set & control. This will be managed by the guix profile.
  • On foreign distro’s, without emacs-guix and other guix dependencies, then getting Guile configured properly while having access to the correct guix binary. You may encounter stability issues down the road. If you run guix pull using the incorrect binary – i.e. you load your emacs profile everywhere so you can start it with systemd – then you’ll eventually pull updates to the wrong guix.
  • But if you mix both straight & guix packages in emacs, you’ll invariably have overlapping dependency trees. If you use native comp, then you’ll need to recompile everything if you update your Emacs binary or build deps. But, for me, doom clean wasn’t working to this end. The reddit post contains more information.
  • Not having emacs-guix is a major impediment to a noob. I’m not a fan of GUI’s generally, but they are a great way to survey the functionality to seed your initial sparse knowledge graph. It can help you ask questions and priortize issues.
  • Not having geiser configured to interoperate at all with emacs-guix or Guile Scheme kept me a noob for way too long.

Don’t take my word for it. I’m not sure on the correct answer for Guix System and Guix on foreign distro’s. I’m still figuring this out. I will update this description with new information and correct opinions.

The main benefits to mixxing guix + setup.el + straight

  • Most of your packages are getting some vetting. The dependencies are ideally deterministic and you can visualize them with guix graph.

Critically, it seems that either straight or setup.el + straight can determine whether dependencies exist locally … AFAIK.

  • So if Guix is providing an Emacs package, then setup won’t tell straight to load it – I have setup.el configured to only load from straight if :straight t is set.
  • Regardless, wouldn’t it be useful if straight decided it didn’t need to pull dependencies or compile? And it should be trivial to detect requireable modules/namespaces. So it probably does because that would be the correct answer to handle as many configuration scenarios as straight.el may encounter.

Why Guix?

The dependencies are spec’d out and reproducible packages can be supplied. You can generate a guix graph of the dependency graph! If it’s not enough that Guix packages offer inheritance, tools like guix import and guix update are available.

The flexibility and low maintainence overhead for personal packages makes maintaining local channels dead simple. I tried RPM and didn’t quite make it to the mock tools. It was fine, but it wasn’t ideal. I didn’t know what ideal was until I saw Guix. No other distributions or package managers offer guix home – they will never have anything like it because they lack the efficiency. There is no purpose to a poor imitation of guix home, since it’s still as complicated as the domain but bundling the packages and services in RPM/Deb and SystemD require about 10x the effort as similar tasks in Guix. Sadly, it takes a long time to develop the chops to get to guix home.

You may need to grok about 2,500 pages of content to get there if you don’t know Scheme … but that’s knowledge you can find in one place, thanks to the GNU documentation. The documentation is good, but there’s a bit of a bootstrapping problem if you don’t have a mentor. If you don’t care about scheme, then you’ll need to study about 250-500 pages, but it’s easy reading.

The scheme is hard. It’s too hard for most people. That’s fine. The difficulty barriers led ArchLinux to be the success that it became. Guix is actually easier, you just don’t realize it.

And why guix system? Because I’ve never learned about Linux this fast. When I wanted a RamFS only image of PXE booting, in one night, I went from:

  • A poor understanding of Grub and bootloaders
  • To grokking the basics of syslinux and pxelinux
  • To understanding u-boot by reading Guix bootloader configs.
  • To seeing configs for multiboot after reading
  • To How do I adjust the post-boot mounting process init/mount disks to load all filesystems into RamFS by mapping/remapping over initramfs/squashfs?
  • To Can Guix load via PXE/TFTP to pull a SquashFS image from HTTPS instead of NFS? So that I can tell if gd macbook pro 2011 has RAM problems or HD problems? Or so I can do something with Dells that don’t have disks?

And no, I can’t answer these questions fully. Guix has some SquashFS functionality, but the bootloader code needs to be modified. Still, you can’t really get around the TFTP limitation of ~100MB. There was a ton of googling there, more gentoo forums/wiki than archwiki… But when I need to confirm the logic of how builds/packages/systems are put together in various scenarios, nothing helps me understand the design of this better than Guix.

So, yeh, I’d like to have a consistent experience with emacs-guix and geiser. And I’d like guix-devel-mode to work.

Why Not Guix Home?

I’ve been pushing forward where I could, trying to minimize moving parts. I hope I haven’t pre-emptively obselesced some future guix-home configuration for Emacs. I think I’ve already obviated any simple means of building Emacs as a set of Guix Home packages/services…

Guix Home elsewhere? Definitely, but I need a realistic migration path. For Emacs, I am also hesitant on trans-lisp configuration DSL’s outside of simple home services – but I need more experience with emacs-lisp before that could be a reasonable problem to deal with. Separating concerns in emacs configs while being able to quickly edit the config is too much for now. The benefits and drawbacks to the process and potentiallys are probably similar to Literate dotfiles – they can provide a standard experience or make projects like ESS/Scimacs/Doom more consistent or replicable.

Here I was also skeptical of how Guix itself would handle edge cases for system config – the immutability, the need to write packages for small things, the service dependencies, the lack of SystemD, lack of nonfree software by default, etc.

However, these turn out to be great limitations:

  • immutability: I don’t have to care really. I just reinstall. Eventually, I may use guix time-machine or be concerned with the specifics of reproducibility.
  • packages for small things: I should’ve been doing this for a decade or longer.
  • services for small things: … ditto.
  • on SystemD: now I appreciate/understand SystemD a bit more and the kind of tools/commands that services or SystemD components utilize.
  • on lack of nonfree software in the ISO: this is complicated. If my Macbook Pro 2011 didn’t run the ISO, I may have assumed Guix was broken. But now I understand, what non-free software runs on my hardware and where it is. I’m a pragmatist, so while I prefer FOSS, but usually end up running a lot of non-free software. But I am a lot more capable of knowing and deciding now.

    So, my perspective/depth on this would be limited or misleading.

Without boundaries, the free energy in a particle simulation disperses quickly – i.e. some limitations can be essential to shape your creativity.

About

A new emacs configuration that's guix.el friendly and hopefully more portable/manageable. From https://github.com/daviwil/dotfiles

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published