hamacs/bootstrap.org
Howard Abrams 35e41b1ee9 Allow non-loaded HAMACS file to be loaded later
While I don't want to automatically load all my projects (for
instance, for programming languages I don't use much), after loading
all files, I then put the rest in the list, allowing me to load them later.
2022-04-09 09:10:55 -07:00

11 KiB
Raw Blame History

My Emacs Bootstrap

A literate programming file for bootstraping my Emacs Configuration.

Introduction

This file contains all the variable definitions and library loading for the other files in my project.

Straight Package Installer

I'm going to be installing everything using the straight.el for package installation and management. However, before I could tangle these org files, I needed to have straight grab the latest org, so the following initialization code is actually in initialize, but the good stuff is:

  (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))

Let's get the Straight project working with use-package:

(straight-use-package 'use-package)

While that enables the :straight t extension to use-package, let's just have that be the default:

(use-package straight
  :custom (straight-use-package-by-default t
           straight-default-vc 'git))

See the details in this essay.

OS Path and Native Compilation

Helper functions to allow code for specific operating systems:

  (defun ha-running-on-macos? ()
    "Return non-nil if running on Mac OS systems."
    (equal system-type 'darwin))

  (defun ha-running-on-linux? ()
    "Return non-nil if running on Linux systems."
    (equal system-type 'gnu/linux))

With the way I start Emacs, I may not have the PATH I actually use (from the shell) available, so we'll force it (code taken from here):

  (defun set-exec-path-from-shell ()
    "Set up Emacs' `exec-path' and PATH environment variable to match
  that used by the user's shell.

  This is particularly useful under Mac OS X and macOS, where GUI
  apps are not started from a shell."
    (interactive)
    (let* ((path-from-shell (shell-command-to-string "echo $PATH"))
           (trimmed-path    (replace-regexp-in-string (rx (zero-or-more space) eol)
                                                      "" path-from-shell))
           (in-fish?        (string-match (rx "fish" eol)
                                          (shell-command-to-string "echo $SHELL")))
           (separator       (if in-fish? " " ":"))
           (env-path        (if in-fish? (replace-regexp-in-string " " ":" trimmed-path) trimmed-path)))
      (message "PATH=%s" path-from-shell)
      (setenv "PATH" env-path)
      (setq exec-path (split-string trimmed-path separator))))

Clear up a Mac-specific issue that sometimes arises since I'm switching to native compilation project, as the Emacs.app that I use doesn't have its bin directory, e.g. Emacs.app/Contents/MacOS/bin:

  (when (ha-running-on-macos?)
      (add-to-list 'exec-path "/usr/local/bin")
      (add-to-list 'exec-path (concat invocation-directory "bin") t))

Getting tired off all the packages that I load spewing a bunch of warnings that I can't do anything about:

  (when (and (fboundp 'native-comp-available-p)
             (native-comp-available-p))
    (setq native-comp-async-report-warnings-errors nil
          native-comp-deferred-compilation t))

GNU Pretty Good Privacy

On Linux, GPG is pretty straight-forward, but on the Mac, I often have troubles doing:

brew install gpg

And I need to install the GPG Suite. While very nice, isn't a GUI I really need, but can take advantage when installed:

  (defun executable (path)
    "Return PATH if it is executable, see `file-executable-p'."
    (when (file-executable-p path) path))

  (use-package epa-file
    :straight (:type built-in)
    :custom (epg-gpg-program (or (executable "/usr/local/MacGPG2/bin/gpg")
                                 (executable "/usr/local/bin/gpg")
                                 (executable "/usr/local/opt/gpg")
                                 (executable "/usr/bin/pgp")))
    :config (epa-file-enable))

Basic Libraries

The following packages come with Emacs, but seems like they still need loading:

  (use-package cl-lib
    :straight (:type built-in)
    :init (defun first (elt) (car elt))
    :commands (first))

  (require 'subr-x)

Ugh. Why am I getting a missing first function error? I define a simple implementation, that the CL library will overwrite … at some point.

While most libraries will take care of their dependencies, I want to install my dependent libraries. Especially, Magnar Sveen's Clojure-inspired dash.el project:

(use-package dash)

Sure this package is essentially syntactic sugar, and to help share my configuration, I attempt to use thread-last instead of ->>, but, I still like it.

The s.el project is a simpler string manipulation library that I (and other projects) use:

(use-package s)

Manipulate file paths with the f.el project:

(use-package f)

My Code Location

Much of my more complicated code comes from my website essays and other projects. The destination, however, shows up here:

(add-to-list 'load-path (f-expand "~/.emacs.d/elisp"))

Hopefully, this will tie me over while I transition.

Emacs Server Control

Sure the Emacs application will almost always have the server-start going, however, I need to control it just a bit (because I often have two instances running on some of my machines). What defines the Emacs instance for work changes … often:

  (defun ha-emacs-for-work? ()
    "Return non-nil when the Emacs application's location matches as one for work.
  Currently, this is the `emacs-plus@28' app that I have built with
  the native-comp model, but I reserve the right to change this."
    (and (f-dir? "~/work")
         (string-match "emacs-plus@28" exec-directory)))

And now start the server with an appropriate tag name:

  (if (not (ha-emacs-for-work?))
      (setq server-name "personal")
    (setq server-name "work")
    (when (ha-running-on-macos?)
      (set-exec-path-from-shell)))

  (server-start)

Load the Rest

The following loads the rest of my org-mode literate files. I add them as they are ready, but eventually, I'll trim this up into a nicer pattern.

  (defvar ha-hamacs-files (flatten-list `("ha-private.org"
                            "ha-config.org"
                            ,(when (display-graphic-p)
                               "ha-display.org")
                            "ha-org.org"
                            ,(when (display-graphic-p)
                               "ha-org-word-processor.org")
                            "ha-org-clipboard.org"
                            "ha-capturing-notes.org"
                            "ha-agendas.org"
                            "ha-passwords.org"
                            "ha-remoting.org"
                            "ha-programming.org"
                            "ha-programming-python.org"
                            ,(if (ha-emacs-for-work?)
                                 '("ha-org-sprint.org" "ha-work.org")
                               ;; Personal Editor
                               '("ha-org-journaling.org"
                                 "ha-irc.org"
                                 "ha-org-publishing.org"
                                 "ha-email.org"
                                 "ha-programming-scheme.org"
                                 "ha-aux-apps.org"
                                 "ha-feed-reader.org"))))
    "List of org files that complete the hamacs project.")

We can test/debug/reload any individual file, via:

  (defun ha-hamacs-load (file)
    "Load or reload an org-mode FILE containing literate Emacs configuration code."
    (interactive (list (completing-read "Org file: " ha-hamacs-files)))
    (let ((full-file (f-join hamacs-source-dir file)))
      (when (f-exists? full-file)
        (org-babel-load-file full-file))))

And we can now load everything:

  (defun ha-hamacs-reload-all ()
    "Reload our entire ecosystem of configuration files."
    (interactive)
    (dolist (file ha-hamacs-files)
      (ha-hamacs-load file)))

And do it:

  (ha-hamacs-reload-all)

Once we have loaded my world, lets add every other Org file in the project to the list, so that I can easily bring more stuff.

  (setq ha-hamacs-files
        (-uniq
         (append ha-hamacs-files
                 (directory-files "~/other/hamacs" nil (rx ".org" eos)))))