1 #+title: =aminb='s Literate Emacs Configuration
4 #+property: header-args :tangle yes
11 This org file is my literate configuration for GNU Emacs, and is
12 tangled to [[./init.el][init.el]]. Packages are installed and managed using
13 [[https://github.com/emacscollective/borg][Borg]]. Over the years, I've taken inspiration from configurations of
14 many different people. Some of the configurations that I can remember
15 off the top of my head are:
17 - [[https://github.com/dieggsy/dotfiles][dieggsy/dotfiles]]: literate Emacs and dotfiles configuration, uses
18 straight.el for managing packages
19 - [[https://github.com/dakra/dmacs][dakra/dmacs]]: literate Emacs configuration, using Borg for managing
21 - [[http://pages.sachachua.com/.emacs.d/Sacha.html][Sacha Chua's literate Emacs configuration]]
22 - [[https://github.com/dakrone/eos][dakrone/eos]]
23 - Ryan Rix's [[http://doc.rix.si/cce/cce.html][Complete Computing Environment]] ([[http://doc.rix.si/projects/fsem.html][about cce]])
24 - [[https://github.com/jwiegley/dot-emacs][jwiegley/dot-emacs]]: nix-based configuration
25 - [[https://github.com/wasamasa/dotemacs][wasamasa/dotemacs]]
26 - [[https://github.com/hlissner/doom-emacs][Doom Emacs]]
28 I'd like to have a fully reproducible Emacs setup (part of the reason
29 why I store my configuration in this repository) but unfortunately out
30 of the box, that's not achievable with =package.el=, not currently
31 anyway. So, I've opted to use Borg. For what it's worth, I briefly
32 experimented with [[https://github.com/raxod502/straight.el][straight.el]], but found that it added about 2 seconds
33 to my init time; which is unacceptable for me: I use Emacs as my
34 window manager (via EXWM) and coming from bspwm, I'm too used to
35 having fast startup times.
39 To use this config for your Emacs, first you need to clone this repo,
40 then bootstrap Borg, tell Borg to retrieve package submodules, and
41 byte-compiled the packages. Something along these lines should work:
43 #+begin_src sh :tangle no
44 git clone https://github.com/aminb/dotfiles ~/.emacs.d
51 * Contents :toc_1:noexport:
55 - [[#initial-setup][Initial setup]]
57 - [[#post-initialization][Post initialization]]
67 #+begin_src emacs-lisp :comments none
68 ;;; init.el --- Amin Bandali's Emacs config -*- lexical-binding: t -*-
71 Enable =view-mode=, which both makes the file read-only (as a reminder
72 that =init.el= is an auto-generated file, not supposed to be edited),
73 and provides some convenient key bindings for browsing through the
78 #+begin_src emacs-lisp :comments none
79 ;; Copyright (C) 2018 Amin Bandali <bandali@gnu.org>
81 ;; This program is free software: you can redistribute it and/or modify
82 ;; it under the terms of the GNU General Public License as published by
83 ;; the Free Software Foundation, either version 3 of the License, or
84 ;; (at your option) any later version.
86 ;; This program is distributed in the hope that it will be useful,
87 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
88 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
89 ;; GNU General Public License for more details.
91 ;; You should have received a copy of the GNU General Public License
92 ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
97 #+begin_src emacs-lisp :comments none
100 ;; Emacs configuration of Amin Bandali, computer scientist and functional
103 ;; THIS FILE IS AUTO-GENERATED FROM `init.org'.
106 ** Naming conventions
108 The conventions below were inspired by [[https://github.com/hlissner/doom-emacs][Doom]]'s, found [[https://github.com/hlissner/doom-emacs/blob/5dacbb7cb1c6ac246a9ccd15e6c4290def67757c/core/core.el#L3-L17][here]].
110 #+begin_src emacs-lisp :comments none
111 ;; Naming conventions:
113 ;; amin-... public variables or non-interactive functions
114 ;; amin--... private anything (non-interactive), not safe for direct use
115 ;; amin/... an interactive function; safe for M-x or keybinding
116 ;; amin|... a hook function
117 ;; amin*... an advising function
118 ;; amin@... a hydra command
124 :CUSTOM_ID: initial-setup
127 #+begin_src emacs-lisp :comments none
134 ** Emacs initialization
136 I'd like to do a couple of measurements of Emacs' startup time. First,
137 let's see how long Emacs takes to start up, before even loading
138 =init.el=, i.e. =user-init-file=:
140 #+begin_src emacs-lisp
141 (defvar amin--before-user-init-time (current-time)
142 "Value of `current-time' when Emacs begins loading `user-init-file'.")
143 (message "Loading Emacs...done (%.3fs)"
144 (float-time (time-subtract amin--before-user-init-time
148 Also, temporarily increase ~gc-cons-threshhold~ and
149 ~gc-cons-percentage~ during startup to reduce garbage collection
150 frequency. Clearing the ~file-name-handler-alist~ seems to help reduce
151 startup time as well.
153 #+begin_src emacs-lisp
154 (defvar amin--gc-cons-threshold gc-cons-threshold)
155 (defvar amin--gc-cons-percentage gc-cons-percentage)
156 (defvar amin--file-name-handler-alist file-name-handler-alist)
157 (setq gc-cons-threshold (* 400 1024 1024) ; 400 MiB
158 gc-cons-percentage 0.6
159 file-name-handler-alist nil
160 ;; sidesteps a bug when profiling with esup
161 esup-child-profile-require-level 0)
164 Of course, we'd like to set them back to their defaults once we're
167 #+begin_src emacs-lisp
171 (setq gc-cons-threshold amin--gc-cons-threshold
172 gc-cons-percentage amin--gc-cons-percentage
173 file-name-handler-alist amin--file-name-handler-alist)))
176 Increase the number of lines kept in message logs (the =*Messages*=
179 #+begin_src emacs-lisp
180 (setq message-log-max 20000)
183 Optionally, we could suppress some byte compiler warnings like below,
184 but for now I've decided to keep them enabled. See documentation for
185 ~byte-compile-warnings~ for more details.
187 #+begin_src emacs-lisp
188 ;; (setq byte-compile-warnings
189 ;; '(not free-vars unresolved noruntime lexical make-local))
194 #+begin_src emacs-lisp
195 (setq user-full-name "Amin Bandali"
196 user-mail-address "amin@aminb.org")
199 ** Package management
203 I can do all my package management things with Borg, and don't need
204 Emacs' built-in =package.el=. Emacs 27 lets us disable =package.el= in
205 the =early-init-file= (see [[https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=24acb31c04b4048b85311d794e600ecd7ce60d3b][here]]).
207 #+begin_src emacs-lisp :tangle early-init.el
208 (setq package-enable-at-startup nil)
211 But since Emacs 27 isn't out yet (Emacs 26 is just around the corner
212 right now), and even when released it'll be long before most distros
213 ship in their repos, I'll still put the old workaround with the
214 commented call to ~package-initialize~ here anyway.
216 #+begin_src emacs-lisp
217 (setq package-enable-at-startup nil)
218 ;; (package-initialize)
224 Assimilate Emacs packages as Git submodules
227 [[https://github.com/emacscollective/borg][Borg]] is at the heart of package management of my Emacs setup. In
228 short, it creates a git submodule in =lib/= for each package, which
229 can then be managed with the help of Magit or other tools.
231 #+begin_src emacs-lisp
232 (setq user-init-file (or load-file-name buffer-file-name)
233 user-emacs-directory (file-name-directory user-init-file))
234 (add-to-list 'load-path
235 (expand-file-name "lib/borg" user-emacs-directory))
239 ;; (require 'borg-nix-shell)
240 ;; (setq borg-build-shell-command 'borg-nix-shell-build-command)
242 (with-eval-after-load 'bind-key
245 ("C-c b A" . borg-activate)
246 ("C-c b a" . borg-assimilate)
247 ("C-c b b" . borg-build)
248 ("C-c b c" . borg-clone)
249 ("C-c b r" . borg-remove)))
255 A use-package declaration for simplifying your .emacs
258 [[https://github.com/jwiegley/use-package][use-package]] is an awesome utility for managing and configuring
259 packages (in our case especially the latter) in a neatly organized way
260 and without compromising on performance.
262 #+begin_src emacs-lisp
263 (require 'use-package)
264 (if nil ; set to t when need to debug init
265 (setq use-package-verbose t
266 use-package-expand-minimally nil
267 use-package-compute-statistics t
269 (setq use-package-verbose nil
270 use-package-expand-minimally t))
276 Browse the Emacsmirror package database
279 Epkg provides access to a local copy of the [[https://emacsmirror.net][Emacsmirror]] package
280 database, low-level functions for querying the database, and a
281 =package.el=-like user interface for browsing the available packages.
283 #+begin_src emacs-lisp
287 (("C-c b d" . epkg-describe-package)
288 ("C-c b p" . epkg-list-packages)
289 ("C-c b u" . epkg-update)))
292 ** No littering in =~/.emacs.d=
295 Help keeping ~/.emacs.d clean
298 By default, even for Emacs' built-in packages, the configuration files
299 and persistent data are all over the place. Use =no-littering= to help
302 #+begin_src emacs-lisp
303 (use-package no-littering
307 (add-to-list 'savehist-additional-variables 'kill-ring)
309 (setq auto-save-file-name-transforms
310 `((".*" ,(no-littering-expand-var-file-name "auto-save/") t))))
313 ** Custom file (=custom.el=)
315 I'm not planning on using the custom file much, but even so, I
316 definitely don't want it mixing with =init.el=. So, here; let's give
317 it it's own file. While at it, treat themes as safe.
319 #+begin_src emacs-lisp
323 (setq custom-file (no-littering-expand-etc-file-name "custom.el"))
324 (when (file-exists-p custom-file)
326 (setf custom-safe-themes t))
331 Load the secrets file if it exists, otherwise show a warning.
333 #+begin_src emacs-lisp
335 (load (no-littering-expand-etc-file-name "secrets")))
338 ** Better =$PATH= handling
340 Let's use [[https://github.com/purcell/exec-path-from-shell][exec-path-from-shell]] to make Emacs use the =$PATH= as set up
343 #+begin_src emacs-lisp
344 (use-package exec-path-from-shell
347 (setq exec-path-from-shell-check-startup-files nil)
349 (exec-path-from-shell-initialize)
350 ;; while we're at it, let's fix access to our running ssh-agent
351 (exec-path-from-shell-copy-env "SSH_AGENT_PID")
352 (exec-path-from-shell-copy-env "SSH_AUTH_SOCK"))
355 ** Only one custom theme at a time
357 #+begin_src emacs-lisp
358 ;; only one custom theme at a time
360 ;; (defadvice load-theme (before clear-previous-themes activate)
361 ;; "Clear existing theme settings instead of layering them"
362 ;; (mapc #'disable-theme custom-enabled-themes))
367 Start server if not already running. Alternatively, can be done by
368 issuing =emacs --daemon= in the terminal, which can be automated with
369 a systemd service or using =brew services start emacs= on macOS. I use
370 Emacs as my window manager (via EXWM), so I always start Emacs on
371 login; so starting the server from inside Emacs is good enough for me.
373 See [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html#Emacs-Server][Using Emacs as a Server]].
375 #+begin_src emacs-lisp
378 :config (or (server-running-p) (server-mode)))
383 Font stack with better unicode support, around =Ubuntu Mono= and
386 #+begin_src emacs-lisp
389 ;; (dolist (ft (fontset-list))
393 ;; (font-spec :name "Source Code Pro" :size 14))
397 ;; (font-spec :name "DejaVu Sans Mono")
400 ;; ;; (set-fontset-font
404 ;; ;; :name "Symbola monospacified for DejaVu Sans Mono")
407 ;; ;; (set-fontset-font
410 ;; ;; (font-spec :name "DejaVu Sans Mono")
416 ;; (font-spec :name "DejaVu Sans Mono" :size 14)
421 ** Gentler font resizing
423 #+begin_src emacs-lisp
424 (setq text-scale-mode-step 1.05)
427 ** Focus follows mouse
429 I’d like focus to follow the mouse when I move the cursor from one
432 #+begin_src emacs-lisp
433 (setq mouse-autoselect-window t)
436 Let’s define a function to conveniently disable this for certain
437 buffers and/or modes.
439 #+begin_src emacs-lisp
440 (defun amin--no-mouse-autoselect-window ()
441 (make-local-variable 'mouse-autoselect-window)
442 (setq mouse-autoselect-window nil))
447 #+begin_src emacs-lisp
454 #+begin_src emacs-lisp
455 (defun amin-enlist (exp)
456 "Return EXP wrapped in a list, or as-is if already a list."
457 (if (listp exp) exp (list exp)))
459 ; from https://github.com/hlissner/doom-emacs/commit/589108fdb270f24a98ba6209f6955fe41530b3ef
460 (defmacro after! (features &rest body)
461 "A smart wrapper around `with-eval-after-load'. Supresses warnings during
463 (declare (indent defun) (debug t))
464 (list (if (or (not (bound-and-true-p byte-compile-current-file))
465 (dolist (next (amin-enlist features))
467 (require next nil :no-error)
468 (load next :no-message :no-error))))
471 (cond ((symbolp features)
472 `(eval-after-load ',features '(progn ,@body)))
473 ((and (consp features)
474 (memq (car features) '(:or :any)))
476 ,@(cl-loop for next in (cdr features)
477 collect `(after! ,next ,@body))))
478 ((and (consp features)
479 (memq (car features) '(:and :all)))
480 (dolist (next (cdr features))
481 (setq body `(after! ,next ,@body)))
484 `(after! (:all ,@features) ,@body)))))
487 Convenience macro for =setq='ing multiple variables to the same value:
489 #+begin_src emacs-lisp
490 (defmacro setq-every! (value &rest vars)
491 "Set all the variables from VARS to value VALUE."
492 (declare (indent defun) (debug t))
493 `(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))
501 #+begin_src emacs-lisp :comments none
508 *** Time and battery in mode-line
510 Enable displaying time and battery in the mode-line, since I'm not
511 using the Xfce panel anymore. Also, I don't need to see the load
512 average on a regular basis, so disable that.
514 Note: using =i3status= on sway at the moment, so disabling this.
516 #+begin_src emacs-lisp :tangle no
519 (setq display-time-default-load-average nil)
525 (display-battery-mode))
530 Might want to set the fringe to a smaller value, especially if using
531 EXWM. I'm fine with the default for now.
533 #+begin_src emacs-lisp
534 ;; (fringe-mode '(3 . 1))
538 *** Disable disabled commands
540 Emacs disables some commands by default that could persumably be
541 confusing for novice users. Let's disable that.
543 #+begin_src emacs-lisp
544 (setq disabled-command-function nil)
549 Save what I copy into clipboard from other applications into Emacs'
550 kill-ring, which would allow me to still be able to easily access it
551 in case I kill (cut or copy) something else inside Emacs before
552 yanking (pasting) what I'd originally intended to.
554 #+begin_src emacs-lisp
555 (setq save-interprogram-paste-before-kill t)
560 #+begin_src emacs-lisp
561 (setq enable-recursive-minibuffers t
562 resize-mini-windows t)
565 *** Lazy-person-friendly yes/no prompts
567 Lazy people would prefer to type fewer keystrokes, especially for yes
568 or no questions. I'm lazy.
570 #+begin_src emacs-lisp
571 (defalias 'yes-or-no-p #'y-or-n-p)
574 *** Startup screen and =*scratch*=
576 Firstly, let Emacs know that I'd like to have =*scratch*= as my
579 #+begin_src emacs-lisp
580 (setq initial-buffer-choice t)
583 Now let's customize the =*scratch*= buffer a bit. First off, I don't
584 need the default hint.
586 #+begin_src emacs-lisp
587 (setq initial-scratch-message nil)
590 Also, let's use Text mode as the major mode, in case I want to
591 customize it (=*scratch*='s default major mode, Fundamental mode,
592 can't really be customized).
594 #+begin_src emacs-lisp
595 (setq initial-major-mode 'text-mode)
598 Inhibit the buffer list when more than 2 files are loaded.
600 #+begin_src emacs-lisp
601 (setq inhibit-startup-buffer-menu t)
604 I don't really need to see the startup screen or echo area message
607 #+begin_src emacs-lisp
608 (advice-add #'display-startup-echo-area-message :override #'ignore)
609 (setq inhibit-startup-screen t
610 inhibit-startup-echo-area-message user-login-name)
613 *** More useful frame titles
615 Show either the file name or the buffer name (in case the buffer isn't
616 visiting a file). Borrowed from Emacs Prelude.
618 #+begin_src emacs-lisp
619 (setq frame-title-format
620 '("" invocation-name " - "
621 (:eval (if (buffer-file-name)
622 (abbreviate-file-name (buffer-file-name))
628 Emacs' default backup settings aren't that great. Let's use more
629 sensible options. See documentation for the ~make-backup-file~
632 #+begin_src emacs-lisp
633 (setq backup-by-copying t
635 delete-old-versions t)
640 Enable automatic reloading of changed buffers and files.
642 #+begin_src emacs-lisp
643 (global-auto-revert-mode 1)
644 (setq auto-revert-verbose nil
645 global-auto-revert-non-file-buffers nil)
648 *** Always use space for indentation
650 #+begin_src emacs-lisp
653 require-final-newline t
659 Enable =winner-mode=.
661 #+begin_src emacs-lisp
665 *** Close =*compilation*= on success
667 #+begin_src emacs-lisp
668 (setq compilation-exit-message-function
669 (lambda (status code msg)
670 "Close the compilation window if successful."
671 ;; if M-x compile exits with 0
672 (when (and (eq status 'exit) (zerop code))
674 (delete-window (get-buffer-window (get-buffer "*compilation*"))))
675 ;; return the result of compilation-exit-message-function
679 *** Search for non-ASCII characters
681 I’d like non-ASCII characters such as ‘’“”«»‹›áⓐ𝒶 to be selected when
682 I search for their ASCII counterpart. Shoutout to [[http://endlessparentheses.com/new-in-emacs-25-1-easily-search-non-ascii-characters.html][endlessparentheses]]
685 #+begin_src emacs-lisp
686 (setq search-default-mode #'char-fold-to-regexp)
688 ;; uncomment to extend this behaviour to query-replace
689 ;; (setq replace-char-fold t)
694 #+begin_src emacs-lisp
698 ("C-c e b" . eval-buffer)
699 ("C-c e r" . eval-region)
701 ("C-c F m" . make-frame-command)
702 ("C-c F d" . delete-frame)
703 ("C-c F D" . delete-other-frames)
705 ("C-c o" . other-window)
707 ("C-c Q" . save-buffers-kill-terminal)
709 ("C-S-h C" . describe-char)
710 ("C-S-h F" . describe-face)
712 ("C-x K" . kill-this-buffer)
714 ("s-p" . beginning-of-buffer)
715 ("s-n" . end-of-buffer))
720 The packages in this section are absolutely essential to my everyday
721 workflow, and they play key roles in how I do my computing. They
722 immensely enhance the Emacs experience for me; both using Emacs, and
725 *** [[https://github.com/emacscollective/auto-compile][auto-compile]]
727 #+begin_src emacs-lisp
728 (use-package auto-compile
731 (auto-compile-on-load-mode)
732 (auto-compile-on-save-mode)
733 (setq auto-compile-display-buffer nil
734 auto-compile-mode-line-counter t
735 auto-compile-source-recreate-deletes-dest t
736 auto-compile-toggle-deletes-nonlib-dest t
737 auto-compile-update-autoloads t)
738 (add-hook 'auto-compile-inhibit-compile-hook
739 'auto-compile-inhibit-compile-detached-git-head))
742 *** [[https://orgmode.org/][Org mode]]
745 Org mode is for keeping notes, maintaining TODO lists, planning
746 projects, and authoring documents with a fast and effective plain-text
750 In short, my favourite way of life.
752 #+begin_src emacs-lisp
756 (setq org-src-tab-acts-natively t
757 org-src-preserve-indentation nil
758 org-edit-src-content-indentation 0
759 org-email-link-description-format "Email %c: %s" ; %.30s
760 org-highlight-latex-and-related '(entities)
762 (add-to-list 'org-structure-template-alist '("L" . "src emacs-lisp") t)
763 (font-lock-add-keywords
765 '(("[ \t]*\\(#\\+\\(BEGIN\\|END\\|begin\\|end\\)_\\(\\S-+\\)\\)[ \t]*\\([^\n:]*\\)"
766 (1 '(:foreground "#5a5b5a" :background "#292b2b") t) ; directive
767 (3 '(:foreground "#81a2be" :background "#292b2b") t) ; kind
768 (4 '(:foreground "#c5c8c6") t))) ; title
770 :bind (:map org-mode-map ("M-L" . org-insert-last-stored-link))
771 :hook ((org-mode . org-indent-mode)
772 (org-mode . auto-fill-mode)
773 (org-mode . flyspell-mode))
775 (org-latex-packages-alist '(("" "listings") ("" "color")))
777 '(org-block-begin-line ((t (:foreground "#5a5b5a" :background "#1d1f21"))))
778 '(org-block ((t (:background "#1d1f21"))))
779 '(org-latex-and-related ((t (:foreground "#b294bb")))))
781 (use-package ox-latex
784 (setq org-latex-listings 'listings
785 ;; org-latex-prefer-user-labels t
787 (add-to-list 'org-latex-packages-alist '("" "listings"))
788 (add-to-list 'org-latex-packages-alist '("" "color"))
789 (add-to-list 'org-latex-classes
790 '("IEEEtran" "\\documentclass[11pt]{IEEEtran}"
791 ("\\section{%s}" . "\\section*{%s}")
792 ("\\subsection{%s}" . "\\subsection*{%s}")
793 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
794 ("\\paragraph{%s}" . "\\paragraph*{%s}")
795 ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
798 (use-package ox-beamer
801 (use-package orgalist
803 :hook (message-mode . orgalist-mode))
806 **** asynchronous tangle
808 =amin/async-babel-tangle= is a function closely inspired by [[https://github.com/dieggsy/dotfiles/tree/cc10edf7701958eff1cd94d4081da544d882a28c/emacs.d#dotfiles][dieggsy's
809 d/async-babel-tangle]] which uses [[https://github.com/jwiegley/emacs-async][async]] to asynchronously tangle an org
812 #+begin_src emacs-lisp
814 (defvar amin-show-async-tangle-results nil
815 "Keep *emacs* async buffers around for later inspection.")
817 (defvar amin-show-async-tangle-time nil
818 "Show the time spent tangling the file.")
820 (defvar amin-async-tangle-post-compile "make ti"
821 "If non-nil, pass to `compile' after successful tangle.")
823 (defun amin/async-babel-tangle ()
824 "Tangle org file asynchronously."
826 (let* ((file-tangle-start-time (current-time))
827 (file (buffer-file-name))
828 (file-nodir (file-name-nondirectory file))
829 (async-quiet-switch "-q"))
833 (org-babel-tangle-file ,file))
834 (unless amin-show-async-tangle-results
838 (message "Tangled %s%s"
840 (if amin-show-async-tangle-time
842 (float-time (time-subtract (current-time)
843 ',file-tangle-start-time)))
845 (when amin-async-tangle-post-compile
846 (compile amin-async-tangle-post-compile)))
847 (message "Tangling %s failed" ,file-nodir))))))))
850 'safe-local-variable-values
851 '(eval add-hook 'after-save-hook #'amin/async-babel-tangle 'append 'local))
854 *** [[https://magit.vc/][Magit]]
857 It's Magit! A Git porcelain inside Emacs.
860 Not just how I do git, but /the/ way to do git.
862 #+begin_src emacs-lisp
865 :bind (("C-x g" . magit-status)
866 ("s-g s" . magit-status)
867 ("s-g l" . magit-log-buffer-file))
869 (magit-add-section-hook 'magit-status-sections-hook
870 'magit-insert-modules
871 'magit-insert-stashes
874 magit-repository-directories '(("~/.emacs.d/" . 0)
876 (nconc magit-section-initial-visibility-alist
877 '(([unpulled status] . show)
878 ([unpushed status] . show)))
879 :custom-face (magit-diff-file-heading ((t (:weight normal)))))
882 *** [[https://github.com/abo-abo/swiper][Ivy]] (and friends)
885 Ivy - a generic completion frontend for Emacs, Swiper - isearch with
886 an overview, and more. Oh, man!
889 There's no way I could top that, so I won't attempt to.
893 #+begin_src emacs-lisp
897 (:map ivy-minibuffer-map
898 ([escape] . keyboard-escape-quit)
899 ([S-up] . ivy-previous-history-element)
900 ([S-down] . ivy-next-history-element)
901 ("DEL" . ivy-backward-delete-char))
906 ;; (ivy-minibuffer-match-face-2 ((t (:background "#e99ce8" :weight semi-bold))))
907 ;; (ivy-minibuffer-match-face-3 ((t (:background "#bbbbff" :weight semi-bold))))
908 ;; (ivy-minibuffer-match-face-4 ((t (:background "#ffbbff" :weight semi-bold))))
914 #+begin_src emacs-lisp
916 :bind (("C-s" . swiper)
922 #+begin_src emacs-lisp
925 :bind (([remap execute-extended-command] . counsel-M-x)
926 ([remap find-file] . counsel-find-file)
927 ("s-r" . counsel-recentf)
928 ("C-c x" . counsel-M-x)
929 ("C-c f ." . counsel-find-file)
930 :map minibuffer-local-map
931 ("C-r" . counsel-minibuffer-history))
934 (defalias 'locate #'counsel-locate))
939 #+begin_src emacs-lisp
944 (eval-when-compile (defvar eshell-prompt-regexp))
945 (defun amin/eshell-quit-or-delete-char (arg)
947 (if (and (eolp) (looking-back eshell-prompt-regexp nil))
948 (eshell-life-is-too-much)
951 (defun amin/eshell-clear ()
953 (let ((inhibit-read-only t))
957 (defun amin|eshell-setup ()
958 (make-local-variable 'company-idle-delay)
959 (setq company-idle-delay nil)
960 (bind-keys :map eshell-mode-map
961 ("C-d" . amin/eshell-quit-or-delete-char)
962 ("C-S-l" . amin/eshell-clear)
963 ("M-r" . counsel-esh-history)
964 ([tab] . company-complete)))
966 :hook (eshell-mode . amin|eshell-setup)
968 (eshell-hist-ignoredups t)
969 (eshell-input-filter 'eshell-input-filter-initial-space))
974 #+begin_src emacs-lisp
978 (("C-x C-b" . ibuffer-other-window)
979 :map ibuffer-mode-map
980 ("P" . ibuffer-backward-filter-group)
981 ("N" . ibuffer-forward-filter-group)
982 ("M-p" . ibuffer-do-print)
983 ("M-n" . ibuffer-do-shell-command-pipe-replace))
985 ;; Use human readable Size column instead of original one
986 (define-ibuffer-column size-h
987 (:name "Size" :inline t)
989 ((> (buffer-size) 1000000) (format "%7.1fM" (/ (buffer-size) 1000000.0)))
990 ((> (buffer-size) 100000) (format "%7.0fk" (/ (buffer-size) 1000.0)))
991 ((> (buffer-size) 1000) (format "%7.1fk" (/ (buffer-size) 1000.0)))
992 (t (format "%8d" (buffer-size)))))
994 (ibuffer-saved-filter-groups
996 ("dired" (mode . dired-mode))
997 ("org" (mode . org-mode))
1006 (mode . eshell-mode)
1007 (mode . shell-mode)))
1008 ("notmuch" (name . "\*notmuch\*"))
1011 (mode . python-mode)
1013 (mode . emacs-lisp-mode)))
1016 (name . "^\\*scratch\\*$")
1017 (name . "^\\*Messages\\*$")))
1020 (name . "^\\*Slack*"))))))
1022 '((mark modified read-only locked " "
1023 (name 18 18 :left :elide)
1025 (size-h 9 -1 :right)
1027 (mode 16 16 :left :elide)
1028 " " filename-and-process)
1032 :hook (ibuffer . (lambda () (ibuffer-switch-to-saved-filter-groups "default"))))
1037 #+begin_src emacs-lisp
1038 (use-package outline
1040 :hook (prog-mode . outline-minor-mode)
1043 outline-minor-mode-map
1044 ("<s-tab>" . outline-toggle-children)
1045 ("M-p" . outline-previous-visible-heading)
1046 ("M-n" . outline-next-visible-heading)
1047 :prefix-map amin--outline-prefix-map
1049 ("TAB" . outline-toggle-children)
1050 ("a" . outline-hide-body)
1051 ("H" . outline-hide-body)
1052 ("S" . outline-show-all)
1053 ("h" . outline-hide-subtree)
1054 ("s" . outline-show-subtree)))
1057 * Borg's =layer/essentials=
1059 #+begin_src emacs-lisp :comments none
1061 ;; * Borg's `layer/essentials'
1064 TODO: break this giant source block down into individual org sections.
1066 #+begin_src emacs-lisp
1068 :config (dash-enable-font-lock))
1070 (use-package diff-hl
1072 (setq diff-hl-draw-borders nil)
1073 (global-diff-hl-mode)
1074 (add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh t))
1078 :config (setq dired-listing-switches "-alh"))
1081 :when (version< "25" emacs-version)
1082 :config (global-eldoc-mode))
1087 (temp-buffer-resize-mode)
1088 (setq help-window-select t))
1091 (setq isearch-allow-scroll t))
1093 (use-package lisp-mode
1095 (add-hook 'emacs-lisp-mode-hook 'outline-minor-mode)
1096 (add-hook 'emacs-lisp-mode-hook 'reveal-mode)
1097 (defun indent-spaces-mode ()
1098 (setq indent-tabs-mode nil))
1099 (add-hook 'lisp-interaction-mode-hook #'indent-spaces-mode))
1103 :config (setq Man-width 80))
1106 :config (show-paren-mode))
1108 (use-package prog-mode
1109 :config (global-prettify-symbols-mode)
1110 (defun indicate-buffer-boundaries-left ()
1111 (setq indicate-buffer-boundaries 'left))
1112 (add-hook 'prog-mode-hook #'indicate-buffer-boundaries-left))
1114 (use-package recentf
1117 (add-to-list 'recentf-exclude "^/\\(?:ssh\\|su\\|sudo\\)?:")
1118 (setq recentf-max-saved-items 40))
1120 (use-package savehist
1121 :config (savehist-mode))
1123 (use-package saveplace
1124 :when (version< "25" emacs-version)
1125 :config (save-place-mode))
1128 :config (column-number-mode))
1130 (progn ; `text-mode'
1131 (add-hook 'text-mode-hook #'indicate-buffer-boundaries-left)
1132 (add-hook 'text-mode-hook #'abbrev-mode))
1137 (add-to-list 'tramp-default-proxies-alist '(nil "\\`root\\'" "/ssh:%h:"))
1138 (add-to-list 'tramp-default-proxies-alist '("localhost" nil nil))
1139 (add-to-list 'tramp-default-proxies-alist
1140 (list (regexp-quote (system-name)) nil nil)))
1142 (use-package undo-tree
1144 (global-undo-tree-mode -1))
1145 ;; :bind (("C-?" . undo-tree-undo)
1146 ;; ("M-_" . undo-tree-redo))
1148 ;; (global-undo-tree-mode)
1149 ;; (setq undo-tree-mode-lighter ""
1150 ;; undo-tree-auto-save-history t))
1155 #+begin_src emacs-lisp :comments none
1162 #+begin_src emacs-lisp
1163 (use-package company
1166 (:map company-active-map
1167 ([tab] . company-complete-common-or-cycle)
1168 ([escape] . company-abort))
1170 (company-minimum-prefix-length 1)
1171 (company-selection-wrap-around t)
1172 (company-dabbrev-char-regexp "\\sw\\|\\s_\\|[-_]")
1173 (company-dabbrev-downcase nil)
1174 (company-dabbrev-ignore-case nil)
1176 (global-company-mode t))
1179 * Syntax and spell checking
1181 #+begin_src emacs-lisp :comments none
1183 ;; * Syntax and spell checking
1186 #+begin_src emacs-lisp
1187 (use-package flycheck
1189 :hook (prog-mode . flycheck-mode)
1191 (:map flycheck-mode-map
1192 ("M-P" . flycheck-previous-error)
1193 ("M-N" . flycheck-next-error))
1195 ;; Use the load-path from running Emacs when checking elisp files
1196 (setq flycheck-emacs-lisp-load-path 'inherit)
1198 ;; Only flycheck when I actually save the buffer
1199 (setq flycheck-check-syntax-automatically '(mode-enabled save)))
1201 ;; http://endlessparentheses.com/ispell-and-apostrophes.html
1205 ;; ’ can be part of a word
1206 (setq ispell-local-dictionary-alist
1207 `((nil "[[:alpha:]]" "[^[:alpha:]]"
1208 "['\x2019]" nil ("-B") nil utf-8)))
1209 ;; don't send ’ to the subprocess
1210 (defun endless/replace-apostrophe (args)
1211 (cons (replace-regexp-in-string
1214 (advice-add #'ispell-send-string :filter-args
1215 #'endless/replace-apostrophe)
1217 ;; convert ' back to ’ from the subprocess
1218 (defun endless/replace-quote (args)
1219 (if (not (derived-mode-p 'org-mode))
1221 (cons (replace-regexp-in-string
1224 (advice-add #'ispell-parse-output :filter-args
1225 #'endless/replace-quote))
1229 #+begin_src emacs-lisp :comments none
1231 ;; * Programming modes
1234 ** [[http://alloytools.org][Alloy]] (with [[https://github.com/dwwmmn/alloy-mode][alloy-mode]])
1236 #+begin_src emacs-lisp
1237 (use-package alloy-mode
1239 :config (setq alloy-basic-offset 2))
1242 ** [[https://coq.inria.fr][Coq]] (with [[https://github.com/ProofGeneral/PG][Proof General]])
1244 #+begin_src emacs-lisp
1245 (use-package proof-site ; Proof General
1247 :load-path "lib/proof-site/generic/")
1250 ** [[https://leanprover.github.io][Lean]] (with [[https://github.com/leanprover/lean-mode][lean-mode]])
1252 #+begin_src emacs-lisp
1253 (eval-when-compile (defvar lean-mode-map))
1254 (use-package lean-mode
1256 :bind (:map lean-mode-map
1257 ("S-SPC" . company-complete))
1259 (require 'lean-input)
1260 (setq default-input-method "Lean"
1261 lean-input-tweak-all '(lean-input-compose
1262 (lean-input-prepend "/")
1263 (lean-input-nonempty))
1264 lean-input-user-translations '(("/" "/")))
1270 *** [[https://github.com/haskell/haskell-mode][haskell-mode]]
1272 #+begin_src emacs-lisp
1273 (use-package haskell-mode
1276 (setq haskell-indentation-layout-offset 4
1277 haskell-indentation-left-offset 4
1278 flycheck-checker 'haskell-hlint
1279 flycheck-disabled-checkers '(haskell-stack-ghc haskell-ghc)))
1282 *** [[https://github.com/jyp/dante][dante]]
1284 #+begin_src emacs-lisp
1287 :commands dante-mode
1288 :hook (haskell-mode . dante-mode))
1291 *** [[https://github.com/mpickering/hlint-refactor-mode][hlint-refactor]]
1293 Emacs bindings for [[https://github.com/ndmitchell/hlint][hlint]]'s refactor option. This requires the refact
1294 executable from [[https://github.com/mpickering/apply-refact][apply-refact]].
1296 #+begin_src emacs-lisp
1297 (use-package hlint-refactor
1299 :bind (:map hlint-refactor-mode-map
1300 ("C-c l b" . hlint-refactor-refactor-buffer)
1301 ("C-c l r" . hlint-refactor-refactor-at-point))
1302 :hook (haskell-mode . hlint-refactor-mode))
1305 *** [[https://github.com/flycheck/flycheck-haskell][flycheck-haskell]]
1307 #+begin_src emacs-lisp
1308 (use-package flycheck-haskell
1309 :after haskell-mode)
1312 *** [[https://github.com/ndmitchell/hlint/blob/20e116a043f2073c57b17b24ae6364b5e433ba7e/data/hs-lint.el][hs-lint.el]]
1314 :header-args+: :tangle lisp/hs-lint.el :mkdirp yes
1317 Currently using =flycheck-haskell= with the =haskell-hlint= checker
1320 #+begin_src emacs-lisp :tangle no
1321 ;;; hs-lint.el --- minor mode for HLint code checking
1323 ;; Copyright 2009 (C) Alex Ott
1325 ;; Author: Alex Ott <alexott@gmail.com>
1326 ;; Keywords: haskell, lint, HLint
1328 ;; Status: distributed under terms of GPL2 or above
1330 ;; Typical message from HLint looks like:
1332 ;; /Users/ott/projects/lang-exp/haskell/test.hs:52:1: Eta reduce
1334 ;; count1 p l = length (filter p l)
1336 ;; count1 p = length . filter p
1341 (defgroup hs-lint nil
1342 "Run HLint as inferior of Emacs, parse error messages."
1346 (defcustom hs-lint-command "hlint"
1347 "The default hs-lint command for \\[hlint]."
1351 (defcustom hs-lint-save-files t
1352 "Save modified files when run HLint or no (ask user)"
1356 (defcustom hs-lint-replace-with-suggestions nil
1357 "Replace user's code with suggested replacements"
1361 (defcustom hs-lint-replace-without-ask nil
1362 "Replace user's code with suggested replacements automatically"
1366 (defun hs-lint-process-setup ()
1367 "Setup compilation variables and buffer for `hlint'."
1368 (run-hooks 'hs-lint-setup-hook))
1370 ;; regex for replace suggestions
1372 ;; ^\(.*?\):\([0-9]+\):\([0-9]+\): .*
1378 (defvar hs-lint-regex
1379 "^\\(.*?\\):\\([0-9]+\\):\\([0-9]+\\): .*[\n\C-m]Found:[\n\C-m]\\s +\\(.*\\)[\n\C-m]Why not:[\n\C-m]\\s +\\(.*\\)[\n\C-m]"
1380 "Regex for HLint messages")
1382 (defun make-short-string (str maxlen)
1383 (if (< (length str) maxlen)
1385 (concat (substring str 0 (- maxlen 3)) "...")))
1387 (defun hs-lint-replace-suggestions ()
1388 "Perform actual replacement of suggestions"
1389 (goto-char (point-min))
1390 (while (re-search-forward hs-lint-regex nil t)
1391 (let* ((fname (match-string 1))
1392 (fline (string-to-number (match-string 2)))
1393 (old-code (match-string 4))
1394 (new-code (match-string 5))
1395 (msg (concat "Replace '" (make-short-string old-code 30)
1396 "' with '" (make-short-string new-code 30) "'"))
1402 (switch-to-buffer (get-file-buffer fname))
1403 (goto-char (point-min))
1404 (forward-line (1- fline))
1406 (setf bline (point))
1407 (when (or hs-lint-replace-without-ask
1410 (setf eline (point))
1412 (setf old-code (regexp-quote old-code))
1413 (while (string-match "\\\\ " old-code spos)
1414 (setf new-old-code (concat new-old-code
1415 (substring old-code spos (match-beginning 0))
1417 (setf spos (match-end 0)))
1418 (setf new-old-code (concat new-old-code (substring old-code spos)))
1419 (remove-text-properties bline eline '(composition nil))
1420 (when (re-search-forward new-old-code eline t)
1421 (replace-match new-code nil t)))))))
1423 (defun hs-lint-finish-hook (buf msg)
1424 "Function, that is executed at the end of HLint execution"
1425 (if hs-lint-replace-with-suggestions
1426 (hs-lint-replace-suggestions)
1429 (define-compilation-mode hs-lint-mode "HLint"
1430 "Mode for check Haskell source code."
1431 (set (make-local-variable 'compilation-process-setup-function)
1432 'hs-lint-process-setup)
1433 (set (make-local-variable 'compilation-disable-input) t)
1434 (set (make-local-variable 'compilation-scroll-output) nil)
1435 (set (make-local-variable 'compilation-finish-functions)
1436 (list 'hs-lint-finish-hook))
1440 "Run HLint for current buffer with haskell source"
1442 (save-some-buffers hs-lint-save-files)
1443 (compilation-start (concat hs-lint-command " \"" buffer-file-name "\"")
1447 ;;; hs-lint.el ends here
1450 #+begin_src emacs-lisp :tangle no
1451 (use-package hs-lint
1453 :bind (:map haskell-mode-map
1454 ("C-c l l" . hs-lint)))
1461 #+begin_src emacs-lisp
1462 (use-package sgml-mode
1465 (setq sgml-basic-offset 2))
1470 #+begin_src emacs-lisp
1471 (use-package css-mode
1474 (setq css-indent-offset 2))
1479 #+begin_src emacs-lisp
1480 (use-package web-mode
1485 web-mode-code-indent-offset
1486 web-mode-css-indent-offset
1487 web-mode-markup-indent-offset))
1492 #+begin_src emacs-lisp
1493 (use-package emmet-mode
1494 :after (:any web-mode css-mode sgml-mode)
1495 :bind* (("C-)" . emmet-next-edit-point)
1496 ("C-(" . emmet-prev-edit-point))
1498 (unbind-key "C-j" emmet-mode-keymap)
1499 (setq emmet-move-cursor-between-quotes t)
1500 :hook (web-mode css-mode html-mode sgml-mode))
1505 #+begin_src emacs-lisp
1506 (use-package nix-mode
1515 #+begin_src emacs-lisp :tangle no
1516 (use-package meghanada
1518 (:map meghanada-mode-map
1519 (("C-M-o" . meghanada-optimize-import)
1520 ("C-M-t" . meghanada-import-all)))
1521 :hook (java-mode . meghanada-mode))
1542 #+begin_src emacs-lisp :tangle no
1543 (use-package treemacs
1544 :config (setq treemacs-never-persist t))
1546 (use-package yasnippet
1548 ;; (yas-global-mode)
1551 (use-package lsp-mode
1552 :init (setq lsp-eldoc-render-all nil
1553 lsp-highlight-symbol-at-point nil)
1558 (use-package company-lsp
1561 (setq company-lsp-cache-candidates t
1562 company-lsp-async t))
1566 (setq lsp-ui-sideline-update-mode 'point))
1568 (use-package lsp-java
1570 (add-hook 'java-mode-hook
1572 (setq-local company-backends (list 'company-lsp))))
1574 (add-hook 'java-mode-hook 'lsp-java-enable)
1575 (add-hook 'java-mode-hook 'flycheck-mode)
1576 (add-hook 'java-mode-hook 'company-mode)
1577 (add-hook 'java-mode-hook 'lsp-ui-mode))
1579 (use-package dap-mode
1585 (use-package dap-java
1588 (use-package lsp-java-treemacs
1592 * Emacs Enhancements
1594 #+begin_src emacs-lisp :comments none
1596 ;; * Emacs Enhancements
1599 ** [[https://github.com/justbur/emacs-which-key][which-key]]
1602 Emacs package that displays available keybindings in popup
1605 #+begin_src emacs-lisp
1606 (use-package which-key
1608 :config (which-key-mode))
1613 #+begin_src emacs-lisp
1614 (add-to-list 'custom-theme-load-path "~/.emacs.d/lisp")
1615 (load-theme 'tangomod t)
1620 #+begin_src emacs-lisp
1621 (use-package doom-modeline
1623 :config (setq doom-modeline-height 32)
1624 :hook (after-init . doom-modeline-init))
1629 #+begin_src emacs-lisp
1630 (use-package doom-themes)
1633 ** theme helper functions
1635 #+begin_src emacs-lisp
1636 (defun amin/lights-on ()
1637 "Enable my favourite light theme."
1640 (mapc #'disable-theme custom-enabled-themes)
1641 (load-theme 'tangomod t)))
1643 (defun amin/lights-off ()
1647 (mapc #'disable-theme custom-enabled-themes)
1648 (load-theme 'doom-tomorrow-night t)))
1651 ("s-t d" . amin/lights-off)
1652 ("s-t l" . amin/lights-on))
1655 ** [[https://github.com/bbatsov/crux][crux]]
1657 #+begin_src emacs-lisp
1660 :bind (("C-c b k" . crux-kill-other-buffers)
1661 ("C-c d" . crux-duplicate-current-line-or-region)
1662 ("C-c D" . crux-duplicate-and-comment-current-line-or-region)
1663 ("C-c f c" . crux-copy-file-preserve-attributes)
1664 ("C-c f d" . crux-delete-file-and-buffer)
1665 ("C-c f r" . crux-rename-file-and-buffer)
1666 ("C-c j" . crux-top-join-line)
1667 ("C-S-j" . crux-top-join-line)))
1670 ** [[https://github.com/alezost/mwim.el][mwim]]
1672 #+begin_src emacs-lisp
1674 :bind (("C-a" . mwim-beginning-of-code-or-line)
1675 ("C-e" . mwim-end-of-code-or-line)
1676 ("<home>" . mwim-beginning-of-line-or-code)
1677 ("<end>" . mwim-end-of-line-or-code)))
1682 #+begin_src emacs-lisp
1683 (use-package projectile
1685 :bind-keymap ("C-c p" . projectile-command-map)
1689 (defun my-projectile-invalidate-cache (&rest _args)
1690 ;; ignore the args to `magit-checkout'
1691 (projectile-invalidate-cache nil))
1693 (eval-after-load 'magit-branch
1695 (advice-add 'magit-checkout
1696 :after #'my-projectile-invalidate-cache)
1697 (advice-add 'magit-branch-and-checkout
1698 :after #'my-projectile-invalidate-cache))))
1701 ** [[https://github.com/Wilfred/helpful][helpful]]
1703 #+begin_src emacs-lisp
1704 (use-package helpful
1707 (("C-S-h c" . helpful-command)
1708 ("C-S-h f" . helpful-callable) ; helpful-function
1709 ("C-S-h v" . helpful-variable)
1710 ("C-S-h k" . helpful-key)
1711 ("C-S-h p" . helpful-at-point)))
1714 ** [[https://github.com/knu/shell-toggle.el][shell-toggle]]
1716 #+begin_src emacs-lisp
1717 (use-package shell-toggle
1719 :bind ("C-c a s e" . amin/shell-toggle)
1721 (defun amin/shell-toggle (make-cd)
1722 "Toggle between the shell buffer and whatever buffer you are editing.
1723 With a prefix argument MAKE-CD also insert a \"cd DIR\" command
1724 into the shell, where DIR is the directory of the current buffer.
1726 When called in the shell buffer returns you to the buffer you were editing
1727 before calling this the first time.
1729 Options: `shell-toggle-goto-eob'"
1731 ;; Try to decide on one of three possibilities:
1732 ;; If not in shell-buffer, switch to it.
1733 ;; If in shell-buffer, return to state before going to the shell-buffer
1734 (if (eq (current-buffer) shell-toggle-shell-buffer)
1735 (shell-toggle-buffer-return-from-shell)
1737 (shell-toggle-buffer-goto-shell make-cd)
1738 (if shell-toggle-full-screen-window-only (delete-other-windows)))))
1740 ;; override to split horizontally instead
1741 (defun shell-toggle-buffer-switch-to-other-window ()
1742 "Switch to other window.
1743 If the current window is the only window in the current frame,
1744 create a new window and switch to it.
1746 \(This is less intrusive to the current window configuration than
1747 `switch-buffer-other-window')"
1748 (let ((this-window (selected-window)))
1750 ;; If we did not switch window then we only have one window and need to
1751 ;; create a new one.
1752 (if (eq this-window (selected-window))
1754 (split-window-horizontally)
1755 (other-window 1)))))
1758 (shell-toggle-launch-shell 'shell-toggle-eshell))
1761 ** [[https://github.com/EricCrosson/unkillable-scratch][unkillable-scratch]]
1763 Make =*scratch*= and =*Messages*= unkillable.
1765 #+begin_src emacs-lisp
1766 (use-package unkillable-scratch
1769 (unkillable-scratch 1)
1771 (unkillable-scratch-behavior 'do-nothing)
1772 (unkillable-buffers '("^\\*scratch\\*$" "^\\*Messages\\*$")))
1775 ** [[https://github.com/davep/boxquote.el][boxquote.el]]
1779 | make pretty boxed quotes like this
1783 #+begin_src emacs-lisp
1784 (use-package boxquote
1787 (:prefix-map amin--boxquote-prefix-map
1789 ("b" . boxquote-buffer)
1790 ("B" . boxquote-insert-buffer)
1791 ("d" . boxquote-defun)
1792 ("F" . boxquote-insert-file)
1793 ("hf" . boxquote-describe-function)
1794 ("hk" . boxquote-describe-key)
1795 ("hv" . boxquote-describe-variable)
1796 ("hw" . boxquote-where-is)
1797 ("k" . boxquote-kill)
1798 ("p" . boxquote-paragraph)
1799 ("q" . boxquote-boxquote)
1800 ("r" . boxquote-region)
1801 ("s" . boxquote-shell-command)
1802 ("t" . boxquote-text)
1803 ("T" . boxquote-title)
1804 ("u" . boxquote-unbox)
1805 ("U" . boxquote-unbox-region)
1806 ("y" . boxquote-yank)
1807 ("M-q" . boxquote-fill-paragraph)
1808 ("M-w" . boxquote-kill-ring-save)))
1811 Also see [[https://www.emacswiki.org/emacs/rebox2][rebox2]].
1813 ** [[https://github.com/DarthFennec/highlight-indent-guides][highlight-indent-guides]]
1815 #+begin_src emacs-lisp
1816 (use-package highlight-indent-guides
1819 :hook ((prog-mode . highlight-indent-guides-mode)
1820 ;; (org-mode . highlight-indent-guides-mode)
1823 (setq highlight-indent-guides-character ?\|)
1824 (setq highlight-indent-guides-auto-enabled nil)
1825 (setq highlight-indent-guides-method 'character)
1826 (setq highlight-indent-guides-responsive 'top)
1827 (set-face-foreground 'highlight-indent-guides-character-face "gainsboro")
1828 (set-face-foreground 'highlight-indent-guides-top-character-face "grey40")) ; grey13 is nice too
1833 #+begin_src emacs-lisp
1834 (use-package pdf-tools
1836 :magic ("%PDF" . pdf-view-mode)
1838 (setq pdf-view-resize-factor 1.05)
1841 (:map pdf-view-mode-map
1842 ("C-s" . isearch-forward)
1843 ("C-r" . isearch-backward)
1844 ("j" . pdf-view-next-line-or-next-page)
1845 ("k" . pdf-view-previous-line-or-previous-page)
1846 ("h" . image-backward-hscroll)
1847 ("l" . image-forward-hscroll)))
1852 #+begin_src emacs-lisp
1858 #+begin_src emacs-lisp
1862 (typo-global-mode 1)
1863 :hook (text-mode . typo-mode))
1868 #+begin_src emacs-lisp
1869 (use-package hl-todo
1872 (global-hl-todo-mode))
1877 #+begin_src emacs-lisp
1878 (use-package shrink-path
1881 (setq eshell-prompt-regexp "\\(.*\n\\)*λ "
1882 eshell-prompt-function #'+eshell/prompt)
1884 (defun +eshell/prompt ()
1885 (let ((base/dir (shrink-path-prompt default-directory)))
1886 (concat (propertize (car base/dir)
1887 'face 'font-lock-comment-face)
1888 (propertize (cdr base/dir)
1889 'face 'font-lock-constant-face)
1890 (propertize (+eshell--current-git-branch)
1891 'face 'font-lock-function-name-face)
1893 (propertize "λ" 'face 'eshell-prompt-face)
1894 ;; needed for the input text to not have prompt face
1895 (propertize " " 'face 'default))))
1897 (defun +eshell--current-git-branch ()
1898 (let ((branch (car (loop for match in (split-string (shell-command-to-string "git branch") "\n")
1899 when (string-match "^\*" match)
1901 (if (not (eq branch nil))
1902 (concat " " (substring branch 2))
1908 Hopefully temporary.
1910 #+begin_src emacs-lisp
1913 :commands (slack-start)
1915 (eval-when-compile ; silence the byte-compiler
1916 (defvar url-http-data nil)
1917 (defvar url-http-extra-headers nil)
1918 (defvar url-http-method nil)
1919 (defvar url-callback-function nil)
1920 (defvar url-callback-arguments nil)
1921 (defvar oauth--token-data nil))
1922 (setq slack-buffer-emojify t
1923 slack-prefer-current-team t)
1925 (slack-register-team
1928 :client-id uw-apv-client-id
1929 :client-secret uw-apv-client-secret
1931 :subscribed-channels '(general)
1932 :full-and-display-names t)
1933 (slack-register-team
1936 :client-id watform-client-id
1937 :client-secret watform-client-secret
1938 :token watform-token
1939 :subscribed-channels '(general)
1940 :full-and-display-names t)
1941 (add-to-list 'swiper-font-lock-exclude 'slack-message-buffer-mode t)
1942 (setq lui-time-stamp-format "[%Y-%m-%d %H:%M:%S]"
1943 lui-time-stamp-only-when-changed-p t
1944 lui-time-stamp-position 'right)
1946 (("C-c s s" . slack-start)
1947 ("C-c s u" . slack-select-unread-rooms)
1948 ("C-c s b" . slack-select-rooms)
1949 ("C-c s t" . slack-change-current-team)
1950 ("C-c s c" . slack-ws-close)
1952 ("M-p" . slack-buffer-goto-prev-message)
1953 ("M-n" . slack-buffer-goto-next-message)
1954 ("C-c e" . slack-message-edit)
1955 ("C-c k" . slack-message-delete)
1956 ("C-c C-k" . slack-channel-leave)
1957 ("C-c r a" . slack-message-add-reaction)
1958 ("C-c r r" . slack-message-remove-reaction)
1959 ("C-c r s" . slack-message-show-reaction-users)
1960 ("C-c p l" . slack-room-pins-list)
1961 ("C-c p a" . slack-message-pins-add)
1962 ("C-c p r" . slack-message-pins-remove)
1963 ("@" . slack-message-embed-mention)
1964 ("#" . slack-message-embed-channel)))
1969 (setq alert-default-style 'notifier))
1972 ** [[https://github.com/peterwvj/eshell-up][eshell-up]]
1974 #+begin_src emacs-lisp
1975 (use-package eshell-up
1981 #+begin_src emacs-lisp
1982 (use-package multi-term
1984 :bind (("C-c C-j" . term-line-mode)
1985 ("C-c a s m m" . multi-term)
1986 ("C-c a s m p" . multi-term-dedicated-toggle))
1988 (setq multi-term-program "/bin/screen"
1989 ;; TODO: add separate bindings for connecting to existing
1990 ;; session vs. always creating a new one
1991 multi-term-dedicated-select-after-open-p t
1992 multi-term-dedicated-window-height 20
1993 multi-term-dedicated-max-window-height 30
1995 '(("C-c C-c" . term-interrupt-subjob)
1996 ("C-c C-e" . term-send-esc)
1998 ("C-y" . term-paste)
1999 ("M-f" . term-send-forward-word)
2000 ("M-b" . term-send-backward-word)
2001 ("M-p" . term-send-up)
2002 ("M-n" . term-send-down)
2003 ("<C-backspace>" . term-send-backward-kill-word)
2004 ("<M-DEL>" . term-send-backward-kill-word)
2005 ("M-d" . term-send-delete-word)
2006 ("M-," . term-send-raw)
2007 ("M-." . comint-dynamic-complete))
2008 term-unbind-key-alist
2009 '("C-z" "C-x" "C-c" "C-h" "C-y" "<ESC>")))
2014 #+begin_src emacs-lisp
2015 (use-package page-break-lines
2017 (global-page-break-lines-mode))
2022 #+begin_src emacs-lisp :comments none
2027 #+begin_src emacs-lisp
2028 (defvar amin-maildir (expand-file-name "~/mail/"))
2030 (add-to-list 'recentf-exclude amin-maildir))
2035 #+begin_src emacs-lisp
2037 amin-gnus-init-file (no-littering-expand-etc-file-name "gnus")
2038 mail-user-agent 'gnus-user-agent
2039 read-mail-command 'gnus)
2042 :bind (("s-m" . gnus)
2043 ("s-M" . gnus-unplugged))
2046 gnus-select-method '(nnnil "")
2047 gnus-secondary-select-methods
2049 (nnimap-stream plain)
2050 (nnimap-address "127.0.0.1")
2051 (nnimap-server-port 143)
2052 (nnimap-authenticator plain)
2053 (nnimap-user "amin@aminb.org"))
2055 (nnimap-stream plain)
2056 (nnimap-address "127.0.0.1")
2057 (nnimap-server-port 143)
2058 (nnimap-authenticator plain)
2059 (nnimap-user "abandali@uwaterloo.ca")))
2060 gnus-message-archive-group "nnimap+amin:Sent"
2064 gnus-large-newsgroup 50
2065 gnus-home-directory (no-littering-expand-var-file-name "gnus/")
2066 gnus-directory (concat gnus-home-directory "news/")
2067 message-directory (concat gnus-home-directory "mail/")
2068 nndraft-directory (concat gnus-home-directory "drafts/")
2069 gnus-save-newsrc-file nil
2070 gnus-read-newsrc-file nil
2071 gnus-interactive-exit nil
2072 gnus-gcc-mark-as-read t))
2074 (use-package gnus-art
2077 gnus-visible-headers
2078 (concat gnus-visible-headers "\\|^List-Id:\\|^X-RT-Originator:\\|^User-Agent:")
2079 gnus-sorted-header-list
2080 '("^From:" "^Subject:" "^Summary:" "^Keywords:"
2081 "^Followup-To:" "^To:" "^Cc:" "X-RT-Originator"
2082 "^Newsgroups:" "List-Id:" "^Organization:"
2083 "^User-Agent:" "^Date:")
2084 ;; local-lapsed article dates
2085 ;; from https://www.emacswiki.org/emacs/GnusFormatting#toc11
2086 gnus-article-date-headers '(user-defined)
2087 gnus-article-time-format
2089 (let* ((date (format-time-string "%a, %d %b %Y %T %z" time))
2090 (local (article-make-date-line date 'local))
2091 (combined-lapsed (article-make-date-line date
2094 (string-match " (.+" combined-lapsed)
2095 (match-string 0 combined-lapsed))))
2096 (concat local lapsed))))
2098 :map gnus-article-mode-map
2099 ("r" . gnus-article-reply-with-original)
2100 ("R" . gnus-article-wide-reply-with-original)
2101 ("M-L" . org-store-link)))
2103 (use-package gnus-sum
2104 :bind (:map gnus-summary-mode-map
2105 :prefix-map amin--gnus-summary-prefix-map
2107 ("r" . gnus-summary-reply)
2108 ("w" . gnus-summary-wide-reply)
2109 ("v" . gnus-summary-show-raw-article))
2112 :map gnus-summary-mode-map
2113 ("r" . gnus-summary-reply-with-original)
2114 ("R" . gnus-summary-wide-reply-with-original)
2115 ("M-L" . org-store-link))
2116 :hook (gnus-summary-mode . amin--no-mouse-autoselect-window))
2118 (use-package gnus-msg
2120 (setq gnus-posting-styles
2122 (address "amin@aminb.org")
2123 (body "\nBest,\namin\n")
2124 (eval (setq amin--message-cite-say-hi t)))
2126 (address "bandali@gnu.org"))
2127 ((header "subject" "ThankCRM")
2128 (to "webmasters-comment@gnu.org")
2129 (body "\nAdded to 2018supporters.html.\n\nMoving to campaigns.\n\n-amin\n")
2130 (eval (setq amin--message-cite-say-hi nil)))
2131 ("nnimap\\+uwaterloo:.*"
2132 (address "abandali@uwaterloo.ca")
2133 (gcc "\"nnimap+uwaterloo:Sent Items\"")))))
2135 (use-package gnus-topic
2136 :hook (gnus-group-mode . gnus-topic-mode))
2138 (use-package gnus-agent
2140 (setq gnus-agent-synchronize-flags 'ask)
2141 :hook (gnus-group-mode . gnus-agent-mode))
2143 (use-package gnus-group
2145 (setq gnus-permanently-visible-groups "\\((INBOX\\|gnu$\\)"))
2147 (use-package mm-decode
2149 (setq mm-discouraged-alternatives '("text/html" "text/richtext")))
2154 #+begin_src emacs-lisp
2155 (use-package sendmail
2157 (setq sendmail-program "/usr/bin/msmtp"
2158 ;; message-sendmail-extra-arguments '("-v" "-d")
2159 mail-specify-envelope-from t
2160 mail-envelope-from 'header))
2165 #+begin_src emacs-lisp
2166 (use-package message
2168 (defconst amin--message-cite-style-format "On %Y-%m-%d %l:%M %p, %N wrote:")
2169 (defconst message-cite-style-bandali
2170 '((message-cite-function 'message-cite-original)
2171 (message-citation-line-function 'message-insert-formatted-citation-line)
2172 (message-cite-reply-position 'traditional)
2173 (message-yank-prefix "> ")
2174 (message-yank-cited-prefix ">")
2175 (message-yank-empty-prefix ">")
2176 (message-citation-line-format
2177 (if amin--message-cite-say-hi
2178 (concat "Hi %F,\n\n" amin--message-cite-style-format)
2179 amin--message-cite-style-format)))
2180 "Citation style based on Mozilla Thunderbird's. Use with message-cite-style.")
2181 (setq message-cite-style 'message-cite-style-bandali
2182 message-kill-buffer-on-exit t
2183 message-send-mail-function 'message-send-mail-with-sendmail
2184 message-sendmail-envelope-from 'header
2185 message-dont-reply-to-names
2186 "\\(\\(.*@aminb\\.org\\)\\|\\(amin@bandali\\.me\\)\\|\\(\\(aminb?\\|mab\\|bandali\\)@gnu\\.org\\)\\|\\(\\(m\\|a\\(min\\.\\)?\\)bandali@uwaterloo\\.ca\\)\\)"
2187 message-user-fqdn "aminb.org")
2188 :hook (;; (message-setup . mml-secure-message-sign-pgpmime)
2189 (message-mode . flyspell-mode)
2190 (message-mode . (lambda ()
2191 ;; (setq fill-column 65
2192 ;; message-fill-column 65)
2193 (make-local-variable 'company-idle-delay)
2194 (setq company-idle-delay 0.2))))
2196 ;; (message-header-subject ((t (:foreground "#111" :weight semi-bold))))
2197 ;; (message-header-to ((t (:foreground "#111" :weight normal))))
2198 ;; (message-header-cc ((t (:foreground "#333" :weight normal))))
2202 (setq mml-secure-openpgp-encrypt-to-self t
2203 mml-secure-openpgp-sign-with-sender t))
2208 Convenient footnotes in =message-mode=.
2210 #+begin_src emacs-lisp
2211 (use-package footnote
2214 (:map message-mode-map
2215 :prefix-map amin--footnote-prefix-map
2217 ("a" . footnote-add-footnote)
2218 ("b" . footnote-back-to-message)
2219 ("c" . footnote-cycle-style)
2220 ("d" . footnote-delete-footnote)
2221 ("g" . footnote-goto-footnote)
2222 ("r" . footnote-renumber-footnotes)
2223 ("s" . footnote-set-style))
2225 (setq footnote-start-tag ""
2227 footnote-style 'unicode))
2232 Manually install bbdb (=lisp/bbdb= copied from an ELPA-based setup),
2233 because installing it from source on Emacs 27 using the following
2234 submodule configuration for some reason doesn’t work and results in
2235 very strange errors when using any of the functions.
2237 #+begin_src conf :tangle no
2240 url = https://git.savannah.nongnu.org/git/bbdb.git
2243 build-step = ./autogen.sh
2244 build-step = ./configure
2246 build-step = make install
2249 I tried using =borg-elpa= instead of doing it like this, but it added
2250 2 seconds to my startup time, which is unacceptable to me.
2252 #+begin_src emacs-lisp
2254 :load-path "lisp/bbdb"
2256 (load (expand-file-name "lisp/bbdb/bbdb-autoloads.el" user-emacs-directory))
2257 ;; (bbdb-mua-auto-update-init 'message)
2258 (setq bbdb-mua-auto-update-p 'query
2259 bbdb-complete-mail nil)
2260 (bbdb-initialize 'gnus 'message))
2265 #+begin_src emacs-lisp
2266 (use-package message-x
2269 (message-x-completion-alist
2271 (("\\([rR]esent-\\|[rR]eply-\\)?[tT]o:\\|[bB]?[cC][cC]:" . gnus-harvest-find-address)
2274 (quote message-newgroups-header-regexp))
2275 message-newgroups-header-regexp message-newsgroups-header-regexp)
2276 . message-expand-group)))))
2281 #+begin_src emacs-lisp
2282 (use-package gnus-harvest
2284 :commands gnus-harvest-install
2287 (if (featurep 'message-x)
2288 (gnus-harvest-install 'message-x)
2289 (gnus-harvest-install)))
2294 #+begin_src emacs-lisp :comments none
2299 ** [[https://ox-hugo.scripter.co][ox-hugo]]
2301 #+begin_src emacs-lisp
2302 (use-package ox-hugo
2305 (use-package ox-hugo-auto-export
2306 :load-path "lib/ox-hugo")
2309 * Post initialization
2311 :CUSTOM_ID: post-initialization
2314 #+begin_src emacs-lisp :comments none
2316 ;; * Post initialization
2319 Display how long it took to load the init file.
2321 #+begin_src emacs-lisp
2322 (message "Loading %s...done (%.3fs)" user-init-file
2323 (float-time (time-subtract (current-time)
2324 amin--before-user-init-time)))
2332 #+begin_src emacs-lisp :comments none
2333 ;;; init.el ends here
2336 * COMMENT Local Variables :ARCHIVE:
2338 # eval: (add-hook 'after-save-hook #'amin/async-babel-tangle 'append 'local)