Aabm's literate Emacs config

Table of Contents

About this configuration

This is Aabm's personal config for GNU Emacs.

This is a configuration mainly oriented around preparation of academic documents using LaTeX and Org-mode, as well as reading other documents using pdf-tools and nov.el, but it can really function for any purpose. This is Emacs, the infinitely extensible editor, after all. This config also aims to provide a framework that can be easily configured by any user, despite being a personal, somewhat long, and opinionated setup. This is done by providing documentation for all settings and keeping the structure of the configuration restricted to only a few files, which are also easy to read and navigate. Some settings for facilitating programming (especially Emacs Lisp) are included here as well, but that is not the main focus.

Some effort has also been taken towards making this configuration look good, mainly by providing the doom-themes, with gruvbox-dark-hard enabled by default.

License

Copyright © 2020 Aabm <aabm@disroot.org>

Author: Aabm <aabm@disroot.org> URL: https://git.snopyta.org/aabm/emacs

This file is NOT part of GNU Emacs.

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with GNU Emacs; see the file LICENSE. If not, you can visit https://www.gnu.org/licenses/gpl-3.0.html or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

User credentials

This section loads my personal credentials file. The contents of the file are minimal, but are kept separate from this file so that distribution of this configuration does not contain any personal information that I'd rather not leak to the public.

;;; Loading personal credentials file
(load-file (concat user-emacs-directory "creds.el"))

If you wish to use the above setting, simply create a file in your user-emacs-directory with the name "creds.el" containing something like the example below:

;;; Example setting for a credentials file:
;; (setq user-full-name "Your Name Here"
;;       user-mail-address "your@email.here"
;;       calendar-latitude 00.00
;;       calendar-longitude 000.00
;;       calendar-location-name "City, State")

Quality of life changes

Enabling "advanced" keybindings

Emacs comes by default with some functions disabled from regular use; calling one of these functions by its respective keybinding will yield a message reminding the user that these are features recommended only to advanced users, and that beginners should turn back. To be honest, I never use any of these features very frequently, but I still don't want to be confronted by a warning message in the rare case I do use any of them. So here we enable these functions:

(put 'dired-find-alternate-file 'disabled nil)
(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)
(put 'narrow-to-region 'disabled nil)
(setq disabled-command-function nil)

Text formatting

Here we make sure all possible text encoding is done as UTF-8, which is universal. We also set code indentation for occasional programming.

;;; Use UTF-8 encoding by default
(prefer-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8) 
(set-keyboard-coding-system 'utf-8) 
(set-selection-coding-system 'utf-8) 
(set-language-environment 'utf-8)
(set-default-coding-systems 'utf-8)
(setq locale-coding-system 'utf-8) 
(setq org-export-coding-system 'utf-8) 

;;; Indentation settings
(setq-default tab-width 4) 

Text display

The settings found here are a bit more varied, but they mostly center around the way text and information is displayed on screen to the user: line numbers, line highlighting, line wrapping, etc.

;;; Display line numbers in programming modes
(add-hook 'prog-mode-hook 'display-line-numbers-mode)

;;; Highlight point line
(add-hook 'prog-mode-hook 'hl-line-mode)
(add-hook 'text-mode-hook 'hl-line-mode)
(add-hook 'org-mode-hook 'hl-line-mode)

;;; Disable line truncation 
(setq truncate-lines nil)
(setq org-startup-truncated nil)

;;; Highlight parent parentheses
(show-paren-mode 1)

;;; Better navigation and display of wrapped lines
(global-visual-line-mode t)

;;; Prettify symbols. Basically converts lambdas in code and other such elements to their respective symbols.
(global-prettify-symbols-mode t)

GUI settings

These are basic setings related to the GUI. This section was originally created for disabling GUI elements like the annoying tool, menu and scroll bars. Now those settings can be found in early-init.el. The settings related to the modeline are independent of the modeline itself; they work with whatever implementation, like Powerline.

;;; Disable default startup screen
(setq inhibit-startup-message t)

;; Display line and comlumn numbers in the modeline
(line-number-mode t)
(column-number-mode t)

Changing defaults

Here we disable or alter undesirable behaviors that Emacs has out of the box. Most notable are the non-conservative scrolling, by which the entire buffer will shift once the cursor wraps over the bottom, and the lack of usage of the X clipboard.

;;; Enable conservative scrolling. Honestly cannot live without this.
(setq scroll-conservatively 100)

;;; Disable bell ring altogether. I have seen some users setting the bell ring to a visual
;; queue, but I think that would be equally as annoying.
(setq ring-bell-function 'ignore)

;;; Use X clipboard. 
(setq x-select-enable-clipboard t)

;;; No autosaving or backup files.
(setq make-backup-files nil) 
(setq auto-save-default nil) 

;;; Replace all yes or no prompts by simple y or n prompts.
(defalias 'yes-or-no-p 'y-or-n-p)

;;; No prompt when killing buffers. This setting may not be advisable to all users.
(setq kill-buffer-query-functions nil)

;;; Auto revert buffers when they change on disk. 
(global-auto-revert-mode t)

Focus follows mouse

With these settings on, the window focus will follow the mouse movement. This is somewhat unorthodox for Emacs, but I find they integrate with desktop environments (which use stacking window managers) much better. You can still change windows using the keyboard, as the focus will not get stuck under whichever window the mouse points to.

(setq focus-follows-mouse t)
(setq mouse-autoselect-window t)

Configuring basic features

Hippie expand

;; (setq hippie-expand-try-functions-list '())

Electric pairs

Electric pairs are quite nice. This feature essentially adds matching closing characters after point once you insert an opening character. Especially good for Lisp programming, what with the parentheses and such.

(setq electric-pair-pairs '(
                           (?\{ . ?\})
                           (?\( . ?\))
                           (?\[ . ?\])
                           (?\" . ?\")
                           ))

(electric-pair-mode t)

Base packages

Async

Async is a library for asynchronous processing for Emacs. By itself it does not do much, but is actually required by some packages. Here we use it mostly for enabling asynchronous operations on files when using Dired and also for compilation of Elisp.

(use-package async
             :straight t
             :init
             (dired-async-mode t)
             (async-bytecomp-package-mode t))

Diminish

Diminish is a package made for hiding minor modes from the modeline display. Personally I don't ever want to see a minor mode in my modeline, so I use it for just about everything. Use-package has quite a nice integration of diminish that makes diminishing modes in an organized fashion during startup very simple.

(use-package diminish
  :straight t
  :diminish
  (page-break-lines-mode visual-line-mode eldoc-mode abbrev-mode org-indent-mode))

Which-key

Which-key is a core package in many distributed configurations for Emacs, and not without reason. It helps the user discover keybindings, default or not, simply by displaying a list of active bindings as the user types. Very useful for the times you can't remember long series of bindings.

(use-package which-key
  :straight t
  :diminish
  :init
  (which-key-mode))

General

General.el is a very powerful package for simplifying custom keybinding declaration. It is used mostly in the Global keybindings section, along with some other miscellaneous occurrences. Here we just ensure it is installed before moving on with configuration.

(straight-use-package 'general)

Swiper/Ivy/Counsel

Ivy is a lightweight but powerful fuzzy completion and narrow search framework for Emacs. It can be used to replace actions like find-file or switch-buffer. Here it is paired with Counsel, which adds further replacements for default actions. We replace the default actions later in this config, by simply overwriting default keybindings with Counsel actions. Ivy-rich adds a few more bits of information to Ivy menus, like the function description when using counsel-M-x.

Swiper is a search tool, for searching for text or regex in-buffer. It pairs nicely with Ivy and Counsel. There is also Avy, which is a buffer navigation tool using narrowing completion. Both of these are later bound to keys.

(use-package ivy
  :straight ivy counsel swiper avy ivy-rich ivy-pass
  :diminish ivy-mode counsel-mode ivy-rich-mode
  :init
  (ivy-mode)
  (counsel-mode)
  (ivy-rich-mode)
  :custom
  (ivy-use-virtual-buffers t)
  (enable-recursive-minibuffers t))

;; (use-package ido-vertical-mode
;;   :straight t
;;   :init
;;   (ido-mode)
;;   (ido-vertical-mode)
;;   :config
;;   (setq ido-vertical-define-keys 'C-n-and-C-p-only))

;; (use-package smex
;;   :straight t
;;   :bind
;;   ("M-x" . smex))

Undo-tree

Undo-tree is a fantastic package that enables a system for visualizing changes to buffers in a branching tree of undos and redos. Here we ensure it is installed and enable it globally.

(use-package undo-tree
  :straight t
  :diminish
  :init
  (global-undo-tree-mode))

Projectile

Projectile is a library for project manipulation.

(use-package projectile
  :straight t
  :diminish
  :init
  (projectile-mode)
  :config
  (define-key projectile-mode-map (kbd "C-x p") 'projectile-command-map)
  :custom
  (projectile-completion-system 'ivy))

Text editing

Company

(use-package company
  :straight t
  :custom
  (company-global-modes '(not eshell-mode shell-mode))
  (company-idle-delay 1)
  (company-minimum-prefix-length 3)
  :diminish
  :init
  (global-company-mode))

;; Use Ctrl instead of Meta for navigating the company prompt
(general-define-key
 :keymaps 'company-active-map
 "M-n" nil
 "M-p" nil
 "C-n" 'company-select-next
 "C-p" 'company-select-previous
 "SPC" 'company-abort
 "ESC" 'company-abort)

Popup kill-ring

(use-package popup-kill-ring
  :straight t
  :bind
  ("M-y" . popup-kill-ring))

Flyspell

(use-package flyspell
  :straight t
  :diminish flyspell-mode)

Expand-region

(use-package expand-region
  :straight t)

Hungry delete

(use-package hungry-delete
  :straight t
  :diminish
  :init
  (hungry-delete-mode))

Writing, notetaking and reading

Org

General settings

;; Set org directory
(setq org-directory "~/docs/org/")

;; Ensure task can't be marked done while dependencies are unfinished
(setq org-enforce-todo-dependencies t)
(setq org-enforce-todo-checkbox-dependencies t)

;; Cosmetic org options
(setq org-ellipsis "↴") 
(setq org-hide-leading-stars t)
(add-hook 'org-mode-hook 'org-indent-mode)


;Enable timestamp and note when closing todos
(setq org-log-done 'time)
;; (setq org-log-done 'note)

;; Enable native tabs in source blocks
(setq org-src-tab-acts-natively t)
;; Enable syntax highlighting in source blocks
(setq org-src-fontify-natively t)
;; Use current window for editing source blocks
(setq org-src-window-setup 'current-window)

Capture

(setq org-default-notes-file (concat org-directory "agenda.org"))
(setq org-capture-templates
      '(("a" "Assignments"
         entry
         (file+headline "agenda.org" "Assignments")
         "* TODO %^{prompt|Política|Antropologia|Sociologia|Economia|Filosofia} - %A\n%?\nDEADLINE: %^T")))

Archive

(setq org-archive-location (concat org-directory "/archive.org::"))

Agenda

(setq org-agenda-files '("~/docs/org/agenda.org"))

Structure templates

(setq org-structure-template-alist
      '(("c" . "center\n")
        ("d" . "src text :tangle ~/.\n")
        ("e" . "src emacs-lisp\n")
        ("h" . "export html\n")
        ("l" . "export latex\n")
        ("q" . "quote\n")
        ("s" . "src")
        ("v" . "verse\n")))

Org-ref

(use-package org-ref
  :straight t
  :custom
  (org-ref-default-bibliography "~/docs/uni/refs.bib"))

LaTeX export template

;; (use-package ox-latex
;;   :after (org ox)
;;   :config
;;   (setq org-latex-default-class "koma-article")
;;   (setq org-latex-compiler "luatex")

;;   ;; Redefine default classes
;;   (setq org-latex-classes
;;         '(("koma-article"
;;            "\\documentclass[
;; ,a4paper
;; ,DIV=12
;; ,12pt
;; ,abstract
;; ,bibliography=totoc
;; ]{scrartcl}

;; \\usepackage[
;; ,babel=english
;; ,header=false
;; ,geometry
;; ,autolang=hyphen
;; ,numbers=osf
;; ]{zpart}

;; \\author{Leo Vivier}"
;;            ("\\section{%s}" . "\\section*{%s}")
;;            ("\\subsection{%s}" . "\\subsection*{%s}")
;;            ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
;;            ("\\paragraph{%s}" . "\\paragraph*{%s}")
;;            ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))))

;;   (setq org-latex-hyperref-template nil)

;;   ;; Use Minted for src-blocks
;;   (setq org-latex-listings 'minted)

;;   ;; Disable defaut packages
;;   (setq org-latex-default-packages-alist nil)

Custom functions

(defun aabm/org-todo-done-and-archive ()
  "Sets current org task do DONE and sends it to org-archive-location."
  (interactive)
  (org-todo 'done)
  (org-archive-subtree))

Custom keybindings

(general-define-key
   :keymaps 'org-mode-map
   "C-M-n" 'org-metadown
   "C-M-p" 'org-metaup
   "M-n" 'org-forward-element
   "M-p" 'org-backward-element
   "C-c C-x C-a" 'aabm/org-todo-done-and-archive)

Org-roam

(use-package org-roam
  :straight t
  :diminish
  :config
  (org-roam-mode)
  (require 'org-roam-protocol)
  :custom
  (org-roam-directory "~/docs/roam/")
  (org-roam-index-file "~/docs/roam/index.org")
  (org-roam-completion-system 'ivy)
  (org-roam-graph-executable "/usr/bin/neato")
  (org-roam-graph-extra-config '(("overlap" . "false")))
  (org-roam-graph-))

(use-package org-roam-server
  :straight t
  :config
  (setq org-roam-server-host "127.0.0.1"
        org-roam-server-port 8080
        org-roam-server-export-inline-images t
        org-roam-server-authenticate nil
        org-roam-server-network-poll t
        org-roam-server-network-arrows nil
        org-roam-server-network-label-truncate t
        org-roam-server-network-label-truncate-length 60
        org-roam-server-network-label-wrap-length 20))

(use-package org-roam-bibtex
  :straight t)

;; Deft is useful for searching through notes
(use-package deft
  :straight t
  :bind
  :custom
  (deft-recursive t)
  (deft-use-filter-string-for-filename t)
  (deft-default-extension "org")
  (deft-directory "~/docs/roam/"))

;; Templates for creating new notes
  (setq org-roam-capture-templates
          '(("t" "tagged" plain (function org-roam--capture-get-point)
           "#+date:%T\n#+startup: overview\n#+roam_tags: %?"
           :file-name "%<%Y%m%d%H%M%S>-${slug}"
           :head "#+title: ${title}\n"
           :unnarrowed t)))

Org-static-blog

(use-package org-static-blog
  :straight t
  :custom
  (org-static-blog-publish-title "test")
  (org-static-blog-publish-url "https://skele.neocities.org/")
  (org-static-blog-publish-directory "~/src/blog/")
  (org-static-blog-posts-directory "/posts")
  (org-static-blog-drafts-directory "~/src/blog/drafts")
  (org-static-blog-enable-tags t)
  (org-export-with-toc t)
  (org-export-with-section-numbers nil)
  (org-static-blog-page-header
   "<meta name=\"author\" content=\"skele\">
<meta name=\"referrer\" content=\"no-referrer\">
<link href= \"static/gruvbox.css\" rel=\"stylesheet\" type=\"text/css\" />
<link rel=\"icon\" href=\"static/favicon.ico\">")
  (org-static-blog-page-preamble
   "<div class=\"header\">
  <a href=\"https://skele.neocities.org\">skele</a>
</div>")
  (org-static-blog-page-postamble
   "<div id=\"archive\">
  <a href=\"https://skele.neocities.org/posts/\">Other posts</a>
</div>
<center><a rel=\"license\" href=\"https://creativecommons.org/licenses/by-sa/3.0/\"><img alt=\"Creative Commons License\" style=\"border-width:0\" src=\"https://i.creativecommons.org/l/by-sa/3.0/88x31.png\" /></a><br /><span xmlns:dct=\"https://purl.org/dc/terms/\" href=\"https://purl.org/dc/dcmitype/Text\" property=\"dct:title\" rel=\"dct:type\">bastibe.de</span> by <a xmlns:cc=\"https://creativecommons.org/ns#\" href=\"https://bastibe.de\" property=\"cc:attributionName\" rel=\"cc:attributionURL\">Bastian Bechtold</a> is licensed under a <a rel=\"license\" href=\"https://creativecommons.org/licenses/by-sa/3.0/\">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.</center>"))

Pdf-tools

(use-package pdf-tools
  :straight t
  :defer nil
  :config
  (pdf-loader-install)
  :custom
  (pdf-view-resize-factor 1.1)
  (pdf-view-continuous nil)
  (pdf-view-display-size 'fit-page)
  :bind (:map pdf-view-mode-map
              ("C-s" . isearch-forward)
              ("C-r" . isearch-backward)
              ("C-c d" . pdf-view-midnight-minor-mode)
              ("C-c z" . aabm/pdf-view-open-in-zathura)
              ("C-c p" . aabm/pdf-view-show-current-page)
              ("C-c t" . aabm/pdf-view-continuous-toggle )))


(use-package org-pdftools
  :straight t
  :hook (org-load . org-pdftools-setup-link))
  :config
  (add-to-list 'org-file-apps 
               '("\\.pdf\\'" . (lambda (file link)
                                 (org-pdfview-open link))))

(defun aabm/pdf-view-continuous-toggle ()
  (interactive)
  (cond ((not pdf-view-continuous)
         (setq pdf-view-continuous t)
         (message "Page scrolling: Continous"))
        (t
         (setq pdf-view-continuous nil)
         (message "Page scrolling: Constrained"))))

(defun aabm/pdf-view-open-in-zathura ()
  "Open the current PDF with ‘zathura’."
  (interactive)
  (save-window-excursion
    (let ((current-file (buffer-file-name))
          (current-page (number-to-string (pdf-view-current-page))))
      (async-shell-command
       (format "zathura -P %s \"%s\"" current-page current-file))))
  (message "Sent to Zathura"))

(defun aabm/pdf-view-show-current-page ()
  "Show the current page."
  (interactive)
  (message "Page: %s" (pdf-view-current-page)))

Writeroom

(use-package writeroom-mode
  :straight t)

Olivetti

(use-package olivetti
  :straight t)

Nov

(use-package nov
  :straight t
  :init
  (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
  :hook
  (nov-mode . olivetti-mode))

Bibtex

;; Ivy-bibtex is a 
(use-package ivy-bibtex
  :straight t
  :bind*
  ("C-x C-r" . ivy-bibtex)
  :custom
  (bibtex-completion-bibliography "~/docs/uni/refs.bib")
  ;; default is to open pdf - change that to insert citation
  (ivy-bibtex-default-action #'ivy-bibtex-insert-citation))
(defalias 'helm-bibtex 'ivy-bibtex)

Other fancy stuff

Magit

(use-package magit
  :straight t)

Dired

(setq dired-dwim-target t)

Shell and terminal emulation

Eshell

;; Setting aliases for use in eshell
(defalias 'open 'find-file-other-window)
(defalias 'clean 'eshell/clear-scrollback)

;; Set a fancy prompt with a lambda
(setq eshell-prompt-regexp "^[^αλ\n]*[αλ] ")
(setq eshell-prompt-function
      (lambda nil
        (concat
         (if (string= (eshell/pwd) (getenv "HOME"))
             (propertize "~" 'face `(:foreground "#458588"))
           (replace-regexp-in-string
            (getenv "HOME")
            (propertize "~" 'face `(:foreground "#458588"))
            (propertize (eshell/pwd) 'face `(:foreground "#458588"))))
         (if (= (user-uid) 0)
             (propertize " α " 'face `(:foreground "#CC241D"))
         (propertize " λ " 'face `(:foreground "#98971A"))))))

(setq eshell-highlight-prompt nil)

(defun aabm/eshell-bindings ()
  "Loads up a bunch of define-keys for eshell-mode-map"
  (define-key eshell-mode-map (kbd "C-c s") 'abm/eshell-sudo-open)
  (define-key eshell-mode-map (kbd "C-c M-w") 'abm/eshell-kill-save-file-at-point)
  (define-key eshell-mode-map (kbd "C-c C-f") 'abm/eshell-find-file-at-point)
  (define-key eshell-mode-map (kbd "C-c e") 'abm/eshell-cat-file-at-point)
  (define-key eshell-mode-map (kbd "C-c m") 'abm/eshell-mkcd)
  (define-key eshell-mode-map (kbd "C-c b") 'abm/eshell-put-last-output-to-buffer))

(add-hook 'eshell-mode-hook 'abm/eshell-bindings)

(defun aabm/eshell-sudo-open (filename)
  "Open a file as root in Eshell."
  (let ((qual-filename (if (string-match "^/" filename)
                           filename
                         (concat (expand-file-name (eshell/pwd)) "/" filename))))
    (switch-to-buffer
     (find-file-noselect
      (concat "/sudo::" qual-filename)))))

(defun aabm/eshell-kill-save-file-at-point ()
    "Copies path to file at point to the kill ring"
    (interactive)
    (let ((file (ffap-file-at-point)))
      (if file
          (kill-new (concat (eshell/pwd) "/" file))
        (user-error "No file at point"))))

(defun aabm/eshell-find-file-at-point ()
  "Finds file under point. Will open a dired buffer if file is a directory."
  (interactive)
  (let ((file (ffap-file-at-point)))
    (if file
        (find-file file)
      (user-error "No file at point"))))

(defun aabm/eshell-cat-file-at-point ()
  "Outputs contents of file at point"
  (interactive)
  (let ((file (ffap-file-at-point)))
    (if file
        (progn
          (end-of-buffer)
          (insert (concat "cat " file))
          (eshell-send-input)))))

(defun aabm/eshell-mkcd (dir)
    "Make a directory, or path, and switch to it."
    (interactive)
    (eshell/mkdir "-p" dir)
    (eshell/cd dir))

(defun aabm/eshell-put-last-output-to-buffer ()
    "Produces a buffer with output of last `eshell' command."
    (interactive)
    (let ((eshell-output (kill-ring-save (eshell-beginning-of-output)
                                         (eshell-end-of-output))))
      (with-current-buffer (get-buffer-create  "*last-eshell-output*")
        (erase-buffer)
        (yank)
        (switch-to-buffer-other-window (current-buffer)))))

Vterm

(use-package vterm
  :straight t)

News and email

Elfeed

(use-package elfeed
  :straight t
  :defer
  :custom
  (elfeed-feeds
  '(("https://paulcockshott.wordpress.com/feed/" blog lefty)
  ("https://blogdaboitempo.com.br/feed/" blog lefty brasil)
  ("https://www.wsws.org/en/rss.xml" news lefty world)
  ("https://cepsongunbr.com/feed" news lefty tankie korea)
  ("https://pcb.org.br/feed/" news lefty org)
  ("https://revistaopera.com.br/feed/" news lefty brasil world)
  ("https://stallman.org/rss/rss.xml" blog tech fsf)
  ("https://brasil.elpais.com/rss/brasil/portada_completo.xml" news brasil)
  ("https://theintercept.com/feed/?lang=pt" news brasil)
  ("https://invidious.snopyta.org/feed/private?token=SOVnhxSPQVjGC2JDrimxCJEVxdIS0Kaqix8aLJfiNQc=" videos invidious youtube)
  ("https://bunkerchan.xyz/tech/index.rss" lefty chan index)
  ("https://blog.riot.im/rss/" tech project privacy blog fsf)
  ("https://nyxt.atlas.engineer/feed" tech project lisp fsf)
  ("https://feed.eugenemolotov.ru/?action=display&bridge=Vk&u=wsnws&format=Atom" vk news world warez pdf))))

mu4e

(use-package mu4e
  :straight t
  :commands mu4e
  :custom
  (mu4e-maildir "~/.mail/disroot/")
  (mu4e-get-mail-command "/usr/bin/mbsync -a")
  (mu4e-html2text-command "/usr/bin/w3m -T text/html")
  (mu4e-drafts-folder "/drafts")
  (mu4e-sent-folder "/sent")
  (mu4e-trash-folder "/trash")
  (message-send-mail-function 'message-send-mail-with-sendmail)
  (sendmail-program "/usr/bin/msmtp")
  (message-sendmail-extra-arguments '("--read-envelope-from"))
  (message-sendmail-f-is-evil 't)
  (mu4e-completing-read-function 'ivy-completing-read)
  (mu4e-confirm-quit nil))

Notmuch

(use-package counsel-notmuch
  :straight notmuch)

Cosmetic packages

Dashboard

(use-package all-the-icons
  :straight t
  :defer nil)

(use-package dashboard
  :straight t
  :defer nil
  :config
  (dashboard-setup-startup-hook)
  :custom
  (dashboard-set-heading-icons t)
  (dashboard-set-file-icons t)
  (dashboard-items
        '((projects . 5)
          (bookmarks . 5)
          (recents . 5)
          (agenda . 10)))
  (dashboard-banner-logo-title "Welcome to GNU Emacs!")
  (dashboard-startup-banner 'official)
  (dashboard-center-content t)
  (dashboard-show-shortcuts t)
  (dashboard-set-init-info t)
  (dashboard-set-footer t)
  (dashboard-footer-messages 
        '("We conjure the spirits of the computer with our spells..."
          "Free as in freedom!"
          "Happy hacking!"
          "The One True Editor, Emacs."
          "Vi Vi Vi, the editor of the beast."
          "Violence begins with Vi."
          "There is no system but GNU, and Linux is one of its kernels."))
  (dashboard-set-navigator t)
  (dashboard-navigator-buttons
        `(;; line1
          ((,nil
            "Config"
            "Open config file for easy editing"
            (lambda (&rest _) (find-file "~/.emacs.d/config.org"))
            'default)
         (nil
          "Magit"
          "Open this config's local git repository"
          (lambda (&rest _) (magit "~/.emacs.d"))
          'default)
           (nil
            "Gitlab"
            "Open this config's Gitlab page in your web browser"
            (lambda (&rest _) (browse-url "https://gitlab.com/aabm/emacs"))
            'default)
           )
          ;; line 2
          ((,nil
            "Email"
            "Read email with mu4e"
            (lambda (&rest _) (mu4e))
            'default)
           (nil
            "Elfeed"
            "Read RSS/Atom feeds with Elfeed"
            (lambda (&rest _) (elfeed))
            'default)
           (nil
            "Novel"
            "Read ebooks with nov.el"
            (lambda (&rest _) (nov-previous-document))
            'default)
           )
          ;; line 3
          ((,nil
            "Terminal"
            "Open vterm"
            (lambda (&rest _) (vterm))
            'default)
           (nil
            "Dired"
            "Manage files with dired"
            (lambda (&rest _) (dired "~/"))
            'default)))))

(setq initial-buffer-choice (lambda () (get-buffer "*dashboard*")))

Beacon

(use-package beacon
  :straight t
  :diminish
  :init
  (beacon-mode))

Powerline

;; (use-package powerline
;;   :straight t
;;   :init
;;   (powerline-default-theme)
;;   :custom
;;   (miniline-default-separator 'arrow))

Doom modeline

(use-package doom-modeline
  :straight t
  :init
  (doom-modeline-mode)
  :custom
  (doom-modeline-height 25)
  (doom-modeline-bar-width 5)
  (doom-modeline-project-detection 'project)
  (doom-modeline-icon (display-graphic-p))
  (doom-modeline-major-mode-icon t)
  (doom-modeline-major-mode-color-icon t)
  (doom-modeline-buffer-state-icon t)
  (doom-modeline-buffer-modification-icon nil)
  (doom-modeline-minor-modes nil)
  (doom-modeline-enable-word-count t)
  (doom-modeline-buffer-encoding nil)
  (doom-modeline-persp-name nil))

Rainbow Delimiters

(use-package rainbow-delimiters
  :straight t
  :diminish rainbow-delimiters-mode
  :hook
  (prog-mode . rainbow-delimiters-mode)
  (text-mode . rainbow-delimiters-mode)
  (org-mode . rainbow-delimiters-mode))

Custom functions and modes

Generate scratch buffers

(defun aabm/generate-org-buffer ()
  "Create and switch to a temporary org mode buffer with a random name."
  (interactive)
  (switch-to-buffer (make-temp-name "org-"))
  (org-mode))

(defun aabm/generate-scratch-buffer ()
  "Create and switch to a temporary scratch buffer with a random name."
  (interactive)
  (switch-to-buffer (make-temp-name "scratch-"))
  (lisp-interaction-mode))

Kill buffer and window

(defun aabm/kill-buffer-and-window ()
  "Kill the current window and kill the buffer it's visiting."
  (interactive)
  (progn
    (kill-buffer)
    (delete-window)))

Kill other buffer and window

(defun aabm/kill-other-buffer-and-window ()
  "Kill the other window and the buffer it's visiting, if there is more than one window."
  (interactive)
  (progn
    (select-window (next-window))
    (aabm/kill-buffer-and-window)))

Kill all file based buffers

(defun aabm/kill-all-buffers ()
    "Kill all file-based buffers."
    (interactive)
    (mapc (lambda (buf) (kill-buffer-if-file buf))
     (buffer-list)))

Window split and follow

(defun aabm/split-follow-window-below ()
  "Creates a window below and automatically switches to it. Meant to be used as a replacement for split-window-below."
  (interactive)
  (split-window-below)
  (balance-windows)
  (other-window 1))

(defun aabm/split-follow-window-right ()
  "Creates a window to the right and automatically switches to it. Meant to be used as a replacement for split-window-right."
  (interactive)
  (split-window-right)
  (balance-windows)
  (other-window 1))

Copy line

(defun aabm/copy-line (arg)
  "Copy lines (as many as prefix argument) to the kill ring. Useful if not using evil-mode."
  (interactive "p")
  (kill-ring-save (line-beginning-position)
                  (line-beginning-position (+ 1 arg)))
  (message "%d line%s copied" arg (if (= 1 arg) "" "s")))

Find org agenda file

(defun aabm/find-org-agenda-file ()
  "Finds the agenda.org file"
  (interactive)
  (find-file (car (org-agenda-files))))

Global keybindings

Defining prefix keys

;; C-z prefix map. 
(global-unset-key "\C-z")
(defalias 'C-z-keymap (make-sparse-keymap))
(defvar C-z-map (symbol-function 'C-z-keymap)
  "Global keymap for characters following C-z.")
(define-key global-map "\C-z" 'C-z-keymap)

Keybindings

(general-define-key
 ;; C-z map
 ;; handling buffers
 "C-z b o" 'aabm/generate-org-buffer
 "C-z b s" 'aabm/generate-scratch-buffer
 "C-z b k" 'aabm/kill-all-buffers

 ;; other
 "C-z r s" 'replace-string
 "C-z r r" 'replace-regexp

 ;; Regular maps
 ;; running major modes
 "C-x s" 'eshell
 "C-x g" 'magit
 "C-x v" 'vterm
 "C-x C-p" 'ivy-pass

 ;; editing text
 "C-x w" 'aabm/copy-line
 "C-=" 'er/expand-region

 ;; window management
 "C-x 2" 'aabm/split-follow-window-below
 "C-x 3" 'aabm/split-follow-window-right

 ;; handling buffers
 "C-x k" 'kill-this-buffer
 "C-x C-k" 'aabm/kill-buffer-and-window
 "C-x C-b" 'ibuffer

 ;; Ivy/Counsel/Swiper/Avy
 "C-s" 'swiper
 "C-r" 'swiper-backward
 "M-s" 'avy-goto-char-2
 "C-x C-f" 'counsel-find-file
 "C-x b" 'counsel-switch-buffer
 "C-x r b" 'counsel-bookmark
 "M-x" 'counsel-M-x
 "C-h f" 'counsel-describe-function
 "C-h v" 'counsel-describe-variable
 "C-h o" 'counsel-describe-symbol
 "M-/" 'counsel-company

 ;; org-mode
 "C-x a" 'org-agenda
 "C-x C-a" 'aabm/find-org-agenda-file
 "C-x c" 'org-capture

 ;; org-roam
 "C-z C-f" 'org-roam-find-file
 "C-z C-l" 'org-roam-insert
 "C-z C-x" 'org-roam-graph
 "C-z C-c" 'org-roam-server-mode
 "C-z C-s" 'deft)

Theming

Select theme

(use-package doom-themes
  :straight t
  :config
  (setq doom-themes-enable-bold t    
        doom-themes-enable-italic t) 
  (setq doom-gruvbox-dark-variant "hard") 
  (doom-themes-org-config))

(load-theme 'doom-gruvbox t)

Frame settings

(set-frame-font "Iosevka 12" nil t)
(set-frame-parameter (selected-frame) 'alpha '(97 95))
(setq frame-title-format "%b")


(add-to-list 'default-frame-alist '(alpha 97 95)) 
(add-to-list 'default-frame-alist '(width  . 110))
(add-to-list 'default-frame-alist '(height . 40))
(add-to-list 'default-frame-alist '(font . "Iosevka 12"))

Things TODO

Keys that can be bound as prefixes

I've deemed the default bindings for these keys to be useless, and as such, plan to eventually change them to something more useful, like a prefix:

  • C-z
  • C-,
  • C-.
  • C-ç

COntinue on with documentation

Currently stopped at Swiper/Ivy/Counsel

Do the hippie-expand thingie so that it only completes with buffer info

Author: Aabm

Created: 2020-08-08 Sat 13:44

Validate