Startup
Initial set-up
We are bootstrapping to some new server and want to stay as self-contained in the .emacs.d directory as possible.
;; we want to replace all calls to `user-emacs-directory' with `initel-directory' (setq initel-directory (file-name-directory (or load-file-name buffer-file-name)))
I carry around two laptops: My main machine runs Linux and my secondary machine runs Windows. I need some mechanism to distinguish between the two platforms
(defconst on-windows (string-equal system-type "windows-nt"))
I pull packages from a server under my control which mirrors the ELPA/MELPA/whatever packages I use in my config. To keep others from accessing it, we keep access password protected. To download from a password-protected ELPA archive, we need to set the appropriate HTTP Basic Auth headers in the call to `url-retrieve`
. This looks like the following. This is not the username, password, or server that is actually used.
(defconst do.bootstrap/archive-url "https://config.example.com/elpa/" "URL to my personal package repository") (defconst do.bootstrap/archive-user "username" "Username for my personal package repository") (defconst do.bootstrap/archive-password "password" "Password for my personal package repository")
We now construct the HTTPS Basic Auth headers for this username/password combination.
(defconst do.bootstrap/archive-auth-str (cons "Authorization" (concat "Basic " (base64-encode-string (concat do.bootstrap/archive-user ":" do.bootstrap/archive-password)))) "HTTPS Basic Auth string for my personal package repository")
Set up `package.el'
to pull from my server.
(require 'package) (setq package-user-dir (concat initel-directory "elpa")) (setq package-native-compile t) (unless on-windows ;; https://lists.gnu.org/archive/html/help-gnu-emacs/2019-08/msg00106.html (setq gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3")) (setq package-archives `(("dennis" . ,do.bootstrap/archive-url)))
`package.el'
uses `url.el'
to retrive the ELPA packages. It used to be that we could give it a URL like https://username:[email protected] and everything works. Unfortunately, this hack seems to have broken in Emacs 29, forcing us to do this the "right" way. So we now advise `url-retrieve'
to set `url-request-extra-headers'
if the archive URL `do.bootstrap/archive-url'
is being requested. This is not necessarily great, but that's what it is.
(defun do.bootstrap/url-retrieve-check-for-archive (orig-fun &rest args) "Like `url-retrive', but check for `do.bootstrap/archive-url' first. If URL starts with that, add the appropriate username and password as extra HTTP headers." ;; the `url' argument is the first argument to the original function (if (string-prefix-p do.bootstrap/archive-url (car args)) ;; if we are requesting from my archive, add the basic auth headers (let ((url-request-extra-headers (cons do.bootstrap/archive-auth-str url-request-extra-headers))) (apply orig-fun args)) ;; else just call `url-retrieve' (apply orig-fun args))) ;; advise `url-retrieve' (advice-add 'url-retrieve :around #'do.bootstrap/url-retrieve-check-for-archive)
Now we can finally initialize `package.el'
. Now, everytime `use-package'
goes out to pull a package from my server, the HTTP Basic Auth headers will be set automatically.
(package-initialize)
Layers and themes
;; We enable or disable one of or several "layers", similar to how spacemacs ;; handles its configuration. Defaults to (defvar do.layers/enabled-layers '(minimal faces org lsp terminal snippets mode-line completion cpp latex octave scheme julia python matlab misc mail) "A list of the enabled Layers for this configuration. Currently available layers: - minimal: The minimum viable configuration - faces: A few tricks with faces, mainly for graphical Emacs - org: `org-mode' customizations - terminal: settings for the terminal environment (`ansi-term') - snippets: `yasnippet' configuration - completion: `company-mode' configuration - mode-line: Custom mode-line - mail: E-Mail configuration - octave: GNU Octave settings - cpp: C and C++ programming environment - matlab: MATLAB programming environment - julia: Julia programming environment - python: Python programming environment - scheme: Scheme programming environment - latex: All things LaTeX (using AUCTeX) - misc: Miscellaneous programming and text environments") ;; We enable one of our themes using this variable (defvar do.theme/enabled-theme 'dark "The choice of theme. The choices are: - dark: Based on the internal `wombat-theme' - light: Based on john2x's plan9-theme - nil: No theme customizations at all")
Site File
;; We can customize the startup for a different machine by incluing elisp in ;; the special file "~/.emacs-site.el". This is loaded before any packages are ;; loaded and any variables set here might be overwritten. However, this can be ;; used to specify different themes or different layers for different machines, ;; for example. (let ((site-file "~/.emacs-site.el")) (when (file-exists-p site-file) (load site-file))) ;; TODO make nicer (let ((site-file "~/.emacs-site/emacs-site.el")) (when (file-exists-p site-file) (load site-file)))
use-package
(unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (setq use-package-verbose t) (eval-when-compile (require 'use-package)) (use-package bind-key :ensure t :demand) (use-package diminish :ensure t :demand)
(use-package dash :ensure t :demand :config (dash-enable-font-lock)) (use-package let-alist :ensure t :demand)
Exec path and other stuff
;; exec path (unless on-windows (use-package exec-path-from-shell :ensure t :init (when (display-graphic-p) (exec-path-from-shell-initialize)))) ;; Moved the custom.el stuff into its own file called ~/.emacs.d/customize.el (setq custom-file (concat initel-directory "customize.el")) (load custom-file) ;; Normally, I could use the =system-name= variable to get the current ;; hostname, but it seems to return the value of =hostname -f=, which is not ;; what I want. Therefore, I find the hostname manually by calling ;; =shell-command-to-string= and stripping some whitespace. This will probably ;; /not/ work on windows. (let ((hn-executable "hostname")) (when (executable-find hn-executable) (setq hostname (->> hn-executable (shell-command-to-string) (replace-regexp-in-string "[ \t\n]*\\'" "") (replace-regexp-in-string "\\`[ \t\n]*" ""))))) ;; ansi-term directory tracking breaks when "system-name" evaluates to ;; "<hostname>.Home". This is a dirty fix, but it works for now. Maybe ;; I can investigate further into this one day. (setq system-name hostname)
Now we are ready to load the rest of the config.