:END:
This org file is my literate configuration for GNU Emacs, and is
-tangled to [[./init.el][init.el]]. Packages are installed and managed using
-[[https://github.com/emacscollective/borg][Borg]]. Over the years, I've taken inspiration from configurations of
-many different people. Some of the configurations that I can remember
-off the top of my head are:
+tangled to [[./init.el][init.el]]. Packages are installed and managed using
+[[https://github.com/raxod502/straight.el][straight.el]]. Over the years, I've taken inspiration from
+configurations of many different people. Some of the configurations
+that I can remember off the top of my head are:
- [[https://github.com/dieggsy/dotfiles][dieggsy/dotfiles]]: literate Emacs and dotfiles configuration, uses
straight.el for managing packages
I'd like to have a fully reproducible Emacs setup (part of the reason
why I store my configuration in this repository) but unfortunately out
of the box, that's not achievable with =package.el=, not currently
-anyway. So, I've opted to use Borg. For what it's worth, I briefly
-experimented with [[https://github.com/raxod502/straight.el][straight.el]], but found that it added about 2 seconds
-to my init time; which is unacceptable for me: I use Emacs as my
-window manager (via EXWM) and coming from bspwm, I'm too used to
-having fast startup times.
+anyway. So, I've opted to use =straight.el=. I also used Borg for a
+few months, but decided to try =straight.el= which allows direct use
+of the various package archives.
** Installation
To use this config for your Emacs, first you need to clone this repo,
-then bootstrap Borg, tell Borg to retrieve package submodules, and
-byte-compiled the packages. Something along these lines should work:
+then tangle =init.org= into =init.el=, and optionally byte-compile
+=init.el=.
+
+First, clone the repository and =cd= into it:
#+begin_src sh :tangle no
git clone https://git.sr.ht/~bandali/dotfiles ~/.emacs.d
cd ~/.emacs.d
-make bootstrap-borg
-make bootstrap
#+end_src
+Then, decide if you would like to use a byte-compiled init file, and
+set the following variable accordingly:
+
+#+begin_src emacs-lisp
+(defvar a/byte-compiled-init t
+ "If non-nil, byte-(re)compile init.el on successful tangles.")
+#+end_src
+
+Now, first tangle =init.org=, and only if you chose to have a
+byte-compiled init, build init as well:
+
+#+begin_src sh :tangle no
+make tangle-init
+make build-init
+#+end_src
+
+If you'd like to use a byte-compiled init, it's important that it be
+recompiled whenever =init.el= is generated from an updated =init.org=.
+Not only does my setup automatically and asynchronously tangle
+=init.org= to =init.el= every time you edit and save =init.org= in GNU
+Emacs, it will also invoke =make build-init= if you set
+=a/byte-compiled-init= to =t= above, so you wouldn't have to worry
+about manually tangling and compiling your init file whenever you
+change it. The output of the last byte-compilation in the current
+session is kept in a =*compilation*= buffer, which will automatically
+be displayed if compilation fails.
+
* Contents :toc_1:noexport:
- [[#about][About]]
*** No =package.el=
-I can do all my package management things with Borg, and don't need
-Emacs' built-in =package.el=. Emacs 27 lets us disable =package.el= in
-the =early-init-file= (see [[https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=24acb31c04b4048b85311d794e600ecd7ce60d3b][here]]).
+I can do all my package management things with =straight.el=, and
+don't need Emacs' built-in =package.el=. Emacs 27 lets us disable
+=package.el= in the =early-init-file= (see [[https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=24acb31c04b4048b85311d794e600ecd7ce60d3b][here]]).
#+begin_src emacs-lisp :tangle early-init.el
(setq package-enable-at-startup nil)
ship in their repos, I'll still put the old workaround with the
commented call to ~package-initialize~ here anyway.
-#+begin_src emacs-lisp
+#+begin_src emacs-lisp :tangle no
(setq package-enable-at-startup nil)
;; (package-initialize)
#+end_src
-*** Borg
+Update: the above is not necessary, since =straight.el= automatically
+does that (and more). See =straight-package-neutering-mode=.
+
+*** =straight.el=
#+begin_quote
-Assimilate Emacs packages as Git submodules
+Next-generation, purely functional package manager for the Emacs
+hacker.
#+end_quote
-[[https://github.com/emacscollective/borg][Borg]] is at the heart of package management of my Emacs setup. In
-short, it creates a git submodule in =lib/= for each package, which
-can then be managed with the help of Magit or other tools.
+=straight.el= allows me to have a fully reproducible Emacs setup.
#+begin_src emacs-lisp
-(setq user-init-file (or load-file-name buffer-file-name)
- user-emacs-directory (file-name-directory user-init-file))
-(add-to-list 'load-path
- (expand-file-name "lib/borg" user-emacs-directory))
;; Main engine start...
-(require 'borg)
+
+(setq straight-repository-branch "develop"
+ straight-check-for-modifications '(check-on-save find-when-checking))
+
+(defun a/bootstrap-straight ()
+ (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)))
+
;; Solid rocket booster ignition...
-(borg-initialize)
+
+(defun a/build-init ()
+ (a/bootstrap-straight)
+ (byte-compile-file "init.el"))
+
+(a/bootstrap-straight)
+
;; We have lift off!
-;; (require 'borg-nix-shell)
-;; (setq borg-build-shell-command 'borg-nix-shell-build-command)
+(setq straight-use-package-by-default t)
+#+end_src
-(with-eval-after-load 'bind-key
- (bind-keys
- :package borg
- ("C-c b A" . borg-activate)
- ("C-c b a" . borg-assimilate)
- ("C-c b b" . borg-build)
- ("C-c b c" . borg-clone)
- ("C-c b r" . borg-remove)))
+Since we enable =straight.el='s =straight-use-package-by-default=
+integration, we will define a =use-feature= for plain ole
+=use-package= without any of the =straight.el= stuff.
+
+#+begin_src emacs-lisp
+(defmacro use-feature (name &rest args)
+ "Like `use-package', but with `straight-use-package-by-default' disabled."
+ (declare (indent defun))
+ `(use-package ,name
+ :straight nil
+ ,@args))
#+end_src
*** =use-package=
and without compromising on performance.
#+begin_src emacs-lisp
-(require 'use-package)
-(if nil ; set to t when need to debug init
- (setq use-package-verbose t
- use-package-expand-minimally nil
- use-package-compute-statistics t
- debug-on-error t)
+(straight-use-package 'use-package)
+(if nil ; set to t when need to debug init
+ (progn
+ (setq use-package-verbose t
+ use-package-expand-minimally nil
+ use-package-compute-statistics t
+ debug-on-error t)
+ (require 'use-package))
(setq use-package-verbose nil
use-package-expand-minimally t))
=package.el=-like user interface for browsing the available packages.
#+begin_src emacs-lisp
+(require 'bind-key)
(use-package epkg
+ :commands (epkg-list-packages epkg-describe-package)
:bind
- (("C-c b d" . epkg-describe-package)
- ("C-c b p" . epkg-list-packages)
- ("C-c b u" . epkg-update))
+ (("C-c P e d" . epkg-describe-package)
+ ("C-c P e p" . epkg-list-packages))
:config
+ (setq epkg-repository "~/.emacs.d/straight/repos/epkgs/")
(eval-when-compile (defvar ivy-initial-inputs-alist))
(with-eval-after-load 'ivy
(add-to-list
it it's own file. While at it, treat themes as safe.
#+begin_src emacs-lisp
-(use-package custom
+(use-feature custom
:no-require t
:config
(setq custom-file (no-littering-expand-etc-file-name "custom.el"))
(use-package exec-path-from-shell
:defer 1
:init
- (setq exec-path-from-shell-check-startup-files nil)
+ (setq exec-path-from-shell-arguments nil
+ exec-path-from-shell-check-startup-files nil)
:config
(exec-path-from-shell-initialize)
;; while we're at it, let's fix access to our running ssh-agent
See [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html#Emacs-Server][Using Emacs as a Server]].
#+begin_src emacs-lisp
-(use-package server
+(use-feature server
:defer 1
:config (or (server-running-p) (server-mode)))
#+end_src
In short, my favourite way of life.
+First, we have to resort to a [[https://github.com/raxod502/straight.el#installing-org-with-straightel][hack]] to be able to use the correct
+latest version of Org from upstream.
+
#+begin_src emacs-lisp
-(use-package org
- :defer 1
+ (use-package git)
+
+ (defun org-git-version ()
+ "The Git version of org-mode.
+ Inserted by installing org-mode or when a release is made."
+ (require 'git)
+ (let ((git-repo (expand-file-name
+ "straight/repos/org/" user-emacs-directory)))
+ (string-trim
+ (git-run "describe"
+ "--match=release\*"
+ "--abbrev=6"
+ "HEAD"))))
+
+ (defun org-release ()
+ "The release version of org-mode.
+ Inserted by installing org-mode or when a release is made."
+ (require 'git)
+ (let ((git-repo (expand-file-name
+ "straight/repos/org/" user-emacs-directory)))
+ (string-trim
+ (string-remove-prefix
+ "release_"
+ (git-run "describe"
+ "--match=release\*"
+ "--abbrev=0"
+ "HEAD")))))
+
+(provide 'org-version)
+#+end_src
+
+We will use the =org-plus-contrib= package to get the whole deal:
+
+#+begin_src emacs-lisp
+(straight-use-package 'org-plus-contrib)
+#+end_src
+
+And here's where my actual Org configurations begin:
+
+#+begin_src emacs-lisp
+(use-feature org
+ :defer 2
:config
(setq org-src-tab-acts-natively t
org-src-preserve-indentation nil
'(org-block ((t (:background "#1d1f21"))))
'(org-latex-and-related ((t (:foreground "#b294bb")))))
-(use-package ox-latex
+(use-feature ox-latex
:after ox
:config
(setq org-latex-listings 'listings
(defvar a/show-async-tangle-time nil
"Show the time spent tangling the file.")
- (defvar a/async-tangle-post-compile "make ti"
+ (defvar a/async-tangle-post-compile
+ (when a/byte-compiled-init "make build-init")
"If non-nil, pass to `compile' after successful tangle.")
+ ;; TODO: look into why directly byte-compiling init.el causes a
+ ;; number of problems, including magit-status not loading (busy
+ ;; waiting).
(defvar a/async-tangle-byte-recompile nil
"If non-nil, byte-recompile the file on successful tangle.")
#+begin_src emacs-lisp
(use-package magit
- :defer 1
+ :defer 2
:bind (("C-x g" . magit-status)
("s-g s" . magit-status)
("s-g l" . magit-log-buffer-file))
Recently opened files.
#+begin_src emacs-lisp
-(use-package recentf
+(use-feature recentf
:defer 0.5
:config
(add-to-list 'recentf-exclude "^/\\(?:ssh\\|su\\|sudo\\)?:")
#+begin_src emacs-lisp
(use-package ivy
- :defer 1
+ :defer 0.6
:bind
(:map ivy-minibuffer-map
([escape] . keyboard-escape-quit)
#+begin_src emacs-lisp
(use-package counsel
- :defer 1
:after ivy
:bind (([remap execute-extended-command] . counsel-M-x)
([remap find-file] . counsel-find-file)
*** eshell
#+begin_src emacs-lisp
-(use-package eshell
- :defer 1
+(use-feature eshell
+ :defer 2
:commands eshell
:bind ("C-c a s e" . eshell)
:config
*** Ibuffer
#+begin_src emacs-lisp
-(use-package ibuffer
+(use-feature ibuffer
:bind
(("C-x C-b" . ibuffer-other-window)
:map ibuffer-mode-map
*** Outline
#+begin_src emacs-lisp
-(use-package outline
+(use-feature outline
:hook (prog-mode . outline-minor-mode)
:bind
(:map
*** Dired
#+begin_src emacs-lisp
-(use-package ls-lisp
+(use-feature ls-lisp
:custom (ls-lisp-dirs-first t))
-(use-package dired
+(use-feature dired
:config
(setq dired-listing-switches "-alh"
ls-lisp-use-insert-directory-program nil)
*** Help
#+begin_src emacs-lisp
-(use-package help
+(use-feature help
:config
(temp-buffer-resize-mode)
(setq help-window-select t))
*** Tramp
#+begin_src emacs-lisp
-(use-package tramp
+(use-feature tramp
:config
(add-to-list 'tramp-default-proxies-alist '(nil "\\`root\\'" "/ssh:%h:"))
(add-to-list 'tramp-default-proxies-alist '("localhost" nil nil))
Display Lisp objects at point in the echo area.
#+begin_src emacs-lisp
-(use-package eldoc
+(use-feature eldoc
:when (version< "25" emacs-version)
:config (global-eldoc-mode))
#+end_src
Highlight matching parens.
#+begin_src emacs-lisp
-(use-package paren
+(use-feature paren
:demand
:config (show-paren-mode))
#+end_src
** simple (for column numbers)
#+begin_src emacs-lisp
-(use-package simple
+(use-feature simple
:config (column-number-mode))
#+end_src
Save minibuffer history.
#+begin_src emacs-lisp
-(use-package savehist
+(use-feature savehist
:config (savehist-mode))
#+end_src
Automatically save place in each file.
#+begin_src emacs-lisp
-(use-package saveplace
+(use-feature saveplace
:when (version< "25" emacs-version)
:config (save-place-mode))
#+end_src
** =prog-mode=
#+begin_src emacs-lisp
-(use-package prog-mode
+(use-feature prog-mode
:config (global-prettify-symbols-mode)
(defun indicate-buffer-boundaries-left ()
(setq indicate-buffer-boundaries 'left))
** =text-mode=
#+begin_src emacs-lisp
-(use-package text-mode
+(use-feature text-mode
:hook ((text-mode . indicate-buffer-boundaries-left)
(text-mode . abbrev-mode)))
#+end_src
#+begin_src emacs-lisp
(use-package company
- :defer 1
+ :defer 3
:bind
(:map company-active-map
([tab] . company-complete-common-or-cycle)
** Lisp
#+begin_src emacs-lisp
-(use-package lisp-mode
+(use-feature lisp-mode
:config
(add-hook 'emacs-lisp-mode-hook 'outline-minor-mode)
(add-hook 'emacs-lisp-mode-hook 'reveal-mode)
#+begin_src emacs-lisp
(use-package alloy-mode
+ :straight (:host github :repo "dwwmmn/alloy-mode")
:config (setq alloy-basic-offset 2))
#+end_src
#+begin_src emacs-lisp
(use-package proof-site ; Proof General
- :load-path "lib/proof-site/generic/")
+ :straight proof-general)
#+end_src
** [[https://leanprover.github.io][Lean]] (with [[https://github.com/leanprover/lean-mode][lean-mode]])
#+begin_src emacs-lisp
(use-package geiser)
-(use-package geiser-guile
+(use-feature geiser-guile
:config
(setq geiser-guile-load-path "~/src/git/guix"))
#+end_src
** guix
#+begin_src emacs-lisp
-(use-package guix
- :load-path "lib/guix/elisp")
+(use-package guix)
#+end_src
* Emacs enhancements
** man
#+begin_src emacs-lisp
-(use-package man
+(use-feature man
:config (setq Man-width 80))
#+end_src
;; prefixes for my personal bindings
"C-c a" "applications"
"C-c a s" "shells"
- "C-c b" "borg"
+ "C-c P" "package-management"
+ "C-c P e" "package-management/epkg"
+ "C-c P s" "package-management/straight.el"
"C-c c" "compile-and-comments"
"C-c e" "eval"
"C-c f" "files"
#+begin_src emacs-lisp
(use-package smart-mode-line
+ :commands (sml/apply-theme)
:demand
:config
(sml/setup))
** [[https://github.com/bbatsov/crux][crux]]
#+begin_src emacs-lisp
-(use-package crux
+(use-package crux ; results in Waiting for git... [2 times]
:defer 1
:bind (("C-c b k" . crux-kill-other-buffers)
("C-c d" . crux-duplicate-current-line-or-region)
#+begin_src emacs-lisp
(use-package helpful
- :defer 1
+ :defer 3
:bind
(("C-S-h c" . helpful-command)
("C-S-h f" . helpful-callable) ; helpful-function
:config
(unkillable-scratch 1)
:custom
- (unkillable-scratch-behavior 'do-nothing)
(unkillable-buffers '("^\\*scratch\\*$" "^\\*Messages\\*$")))
#+end_src
#+begin_src emacs-lisp
(use-package multi-term
- :defer 1
+ :defer 3
:bind (("C-c a s m" . multi-term-dedicated-toggle)
:map term-mode-map
("C-c C-j" . term-char-mode)
mail-user-agent 'gnus-user-agent
read-mail-command 'gnus)
-(use-package gnus
+(use-feature gnus
:bind (("s-m" . gnus)
("s-M" . gnus-unplugged))
:init
gnus-save-newsrc-file nil
gnus-read-newsrc-file nil
gnus-interactive-exit nil
- gnus-gcc-mark-as-read t))
+ gnus-gcc-mark-as-read t)
+ :config
+ (require 'ebdb)
+ (require 'ebdb-mua)
+ (require 'ebdb-gnus))
-(use-package gnus-art
+(use-feature gnus-art
:config
(setq
gnus-visible-headers
("R" . gnus-article-wide-reply-with-original)
("M-L" . org-store-link)))
-(use-package gnus-sum
+(use-feature gnus-sum
:bind (:map gnus-summary-mode-map
:prefix-map a/gnus-summary-prefix-map
:prefix "v"
("M-L" . org-store-link))
:hook (gnus-summary-mode . a/no-mouse-autoselect-window))
-(use-package gnus-msg
+(use-feature gnus-msg
:config
(setq gnus-posting-styles
'((".*"
(address "abandali@uwaterloo.ca")
(gcc "\"nnimap+uwaterloo:Sent Items\"")))))
-(use-package gnus-topic
+(use-feature gnus-topic
:hook (gnus-group-mode . gnus-topic-mode))
-(use-package gnus-agent
+(use-feature gnus-agent
:config
(setq gnus-agent-synchronize-flags 'ask)
:hook (gnus-group-mode . gnus-agent-mode))
-(use-package gnus-group
+(use-feature gnus-group
:config
(setq gnus-permanently-visible-groups "\\((INBOX\\|gnu$\\)"))
-(use-package mm-decode
+(use-feature mm-decode
:config
(setq mm-discouraged-alternatives '("text/html" "text/richtext")))
#+end_src
** sendmail
#+begin_src emacs-lisp
-(use-package sendmail
+(use-feature sendmail
:config
(setq sendmail-program "/usr/bin/msmtp"
;; message-sendmail-extra-arguments '("-v" "-d")
** message
#+begin_src emacs-lisp
-(use-package message
+(use-feature message
:config
(defconst a/message-cite-style-format "On %Y-%m-%d %l:%M %p, %N wrote:")
(defconst message-cite-style-bandali
message-dont-reply-to-names
"\\(\\(.*@aminb\\.org\\)\\|\\(amin@bandali\\.me\\)\\|\\(\\(aminb?\\|mab\\|bandali\\)@gnu\\.org\\)\\|\\(\\(m\\|a\\(min\\.\\)?\\)bandali@uwaterloo\\.ca\\)\\)"
message-user-fqdn "aminb.org")
+ (require 'company-ebdb)
:hook (;; (message-setup . mml-secure-message-sign-pgpmime)
(message-mode . flyspell-mode)
(message-mode . (lambda ()
Convenient footnotes in =message-mode=.
#+begin_src emacs-lisp
-(use-package footnote
+(use-feature footnote
:after message
:bind
(:map message-mode-map
#+begin_src emacs-lisp
(use-package ebdb
- :defer 2
+ :straight (:host github :repo "girzel/ebdb")
:after gnus
:bind (:map gnus-group-mode-map ("e" . ebdb))
:config
(with-eval-after-load 'swiper
(add-to-list 'swiper-font-lock-exclude 'ebdb-mode t)))
-(use-package ebdb-com
+(use-feature ebdb-com
:after ebdb)
;; (use-package ebdb-complete
;; (ebdb-complete-enable))
(use-package company-ebdb
- :defer 2
:config
(defun company-ebdb--post-complete (_) nil))
-(use-package ebdb-gnus
- :defer 3
+(use-feature ebdb-gnus
:after ebdb
:custom
(ebdb-gnus-window-configuration
(article 1.0)
(ebdb-gnus 0.3))))))
-(use-package ebdb-mua
- :defer 3
+(use-feature ebdb-mua
:after ebdb
;; :custom (ebdb-mua-pop-up nil)
)
(use-package ox-hugo
:after ox)
-(use-package ox-hugo-auto-export
- :load-path "lib/ox-hugo")
+(use-feature ox-hugo-auto-export
+ :after ox-hugo)
#+end_src
* Post initialization