Notice: This page is duel licensed CC-BY-SA 4.0 and the GPLv3.
Source files available at git.sr.ht/~taingram/emacs-init
GNU Emacs is a free (as in freedom) text editor for writing and code. You can read more about Emacs and it's history on Wikipedia.
If you are interested in learning Emacs check out the guided tour and
the internal Emacs Tutorial (from within Emacs type Ctrl + h then
type t). In addition, if you are interested in using Emacs for
general writing (not programming) check out Org-mode, its great!
1. Why use GNU Emacs?
As a professional email writer (lol), amateur blogger, and programmer my primary input/output to the computer is through text. Emacs provides me with a solid text editor that has some standout features:
- Extensibility — a complete programming interface for enhancing my own user experience and automating repetitive tasks.
- Portable — a portable environment that works on all major operating systems. (Not all of us have the luxury of using GNU/Linux at work)
- Universal Interface — a universal text based interface for all tasks involving text. In addition, it's a consistent and distraction free interface all tasks.
- Community — Great community developing high quality packages. (magit, org-mode, eshell, etc.)
- Free Software — The ability to access and modify all the source code of Emacs allows for complete customization. The source code also provides an excellent resource for those wishing to learn Lisp, programming, and programming language development1. This factor combined with a rich history and an enthusiastic community ensure that Emacs will not disappear any time soon.
1.1. Emacs Lisp
One aside on Emacs Lisp, which is often disparaged as the worst surviving Lisp dialect. I will not argue that point directly, but I will posit that Emacs Lisp is a more than capable Lisp and very pleasant work in.
The surprising strength of Emacs Lisp is well captured in this excerpt from the Emacs calculator (calc) manual:
I chose Emacs Lisp, a) because I had always been curious about it and b) because, being only a text editor extension language after all, Emacs Lisp would surely reach its limits long before the project got too far out of hand.
To make a long story short, Emacs Lisp turned out to be a distressingly solid implementation of Lisp, and the humble task of calculating turned out to be more open-ended than one might have expected.
1.2. Shortcomings
A minor problem is the limited support for concurrency which causes some actions complete slowly or lock-up Emacs. However, I rarely find this causes significant annoyances. In most situations computationally intensive actions can be handed off to a separate Emacs process (see info:elisp#Processes) or a separate program entirely (e.g. using isync to retrieve mail).
Beyond technical limitations my main issue with Emacs is I cannot use it all the time. With the huge investment I've made on my computer it would be wonderful to have the power of Emacs in a smartphone type package. However, touchscreen displays do not translate well to the Emacs workflow. I continue to yearn for an ideal Emacs PDA.
1.3. Thoughts from other Emacs Users
I've found both these video essays by Protesilaos Stavrou to be a great summary of the thought process involved for why someone would want to use Emacs:
2. Using a Literate Configuration with Org Mode
My Emacs configuration file is written in a literate programming-like style which allows for prose to be mixed with source code blocks. From that the relevant source blocks are extracted and copied to my Emacs configuration file. You are reading an HTML export of this file right now. Everything that follows is exported from my actual Emacs configuration.
I had held out for many years on creating a literate config, but seeing other users' success convinced me. The ability to maintain complete notes, links, and the configuration code all in one file is extremely convenient. In addition, the hierarchical structure of Org allows for a clearer organization of the code.
Please note though, this is my actual emacs configuration, so this page will change often, and may include incomplete or broken settings. I will try to flag work-in-progress sections with TODO/WIP keywords as I develop those sections.
2.1. Literate Config Setup
I have one org file init.org where I combine all of my Emacs configuration
code with prose notes about it. That org file can be placed anywhere on my
system because it is not the actual initialization file used by Emacs. From
the org file my actual init.el is exported (tangled) from the elisp source
blocks. In literate programming terms, the org file is where coded and
prose is woven together, then code is tangled out to just elisp that can be
evaluated by Emacs. That means using a literate config imposes no startup
or runtime performance penalty.
Adding the following to your org file will copy (tangle) the code
blocks into your init.el file when you run org-babel-tangle (C-c
C-v t).
#+PROPERTY: header-args :results silent :tangle "~/.config/emacs/init.el"
To exclude specific source blocks from being tangled add :tangle no
to the header.
I use the package org-auto-tangle (available on NonGNU ELPA) to automatically tangle the file on save. This can be enabled by adding the following to the org file.
#+AUTO_TANGLE: t
Enable lexical bindings in the exported Emacs Lisp file:
;;; init.el -*- lexical-binding: t; -*-
Lexical binding can be enabled for all Emacs Lisp source blocks to ensure proper evaluation when writing and testing them individually.
(setq org-babel-default-header-args:emacs-lisp '((:lexical . "yes")))
2.2. Avoid Tangling Blocks on Certain Operating Systems
Use the below functions in the tangle headers to control whether blocks are excluded or included for certain operating systems.
(defun tangle-if-linux () (if (eq system-type 'gnu/linux) "yes" "no")) (defun tangle-if-windows () (if (eq system-type 'windows-nt) "yes" "no"))
To include a block for a certain operating system add :tangle to the
block header arguments.
#+begin_src emacs-lisp :tangle (tangle-if-linux)
2.3. Using this Configuration File
The complete Org file is available on sourcehut. However, I would not recommend copying this configuration directly as it is tailored for my particular usage. Instead I recommend skimming through this article, copy the sections that interest you, and adjust them to your preferences. Emacs is your editor and if it does not reflect your preferences then you are not using it correctly.
3. Emacs Startup Settings
3.1. Early Init
Using an early-init.el file can speed up Emacs startup, by avoiding loading
unnecessary UI elements. Below is my complete early-init.el:
;;; early-init.el --- Early initialization -*- lexical-binding: t -*- ;;; Commentary: ;;; Code: ;; Disable GUI (tool-bar-mode -1) (setq use-dialog-box t) (setq use-file-dialog nil) (setq-default frame-title-format '("%b - GNU Emacs @" system-name)) ;; Hide the startup screen (setq inhibit-startup-screen t) ;; Increase font size (set-face-attribute 'default nil :height 130) ;; Disable bell sound. (setq ring-bell-function 'ignore) ;; Set HOME for MS Windows systems (when (eq system-type 'windows-nt) (setq user-init-file "C:/Users/thomasingram/.emacs.d/init.el") (setq user-emacs-directory "C:/Users/thomasingram/.emacs.d/") (setq default-directory "C:/Users/thomasingram/") (setenv "HOME" "C:/Users/thomasingram/")) ;; Helper functions for tangling init.org file (defun tangle-if-linux () (if (eq system-type 'gnu/linux) "yes" "no")) (defun tangle-if-windows () (if (eq system-type 'windows-nt) "yes" "no")) ;;; early-init.el ends here
3.2. MS Windows Related Settings
3.2.1. Reset Default-Directory on Windows
(when (eq system-type 'windows-nt) (setq default-directory "~/"))
3.2.2. Zip/Unzip Binaries Windows
Sometimes Emacs expects to have access to zip/unzip utilities. I've downloaded the Windows ports from GnuWin32. I've noticed this is needed to generate ODT documents in Org-mode exporting as well as installing Language Servers for Eglot.
(add-to-list 'exec-path "C:/Users/thomasingram/OneDrive - oakland.edu/Apps/GnuWin32/bin")
3.2.3. Add MS Office to Path
This is useful for quickly opening files in Excel from eshell or dired.
(add-to-list 'exec-path "C:/Program Files/Microsoft Office/root/Office16")
Disclaimer: if you are working outside of a large organization then you likely do not need to use Microsoft's office suite of software. I would strongly recommend utilizing free & open source alternatives like Libre Office.
3.3. Prefer UTF-8
(prefer-coding-system 'utf-8)
3.4. Customization Menus
Emacs has its own customization functionality which can be useful for
experimenting and finding new Emacs options. Normally these settings
are appended to the end of the user's init file, setting
custom-variable will save it there.
(setq custom-file (concat user-emacs-directory "customizations.el"))
Some prefer not to use this functionality as they prefer to code elisp themselves, but even if you do not use the customization interface loading it is still useful for setting safe file variables and themes.
(load custom-file 't)
3.4.1. Show Variable Names in Customize Menus
The customization menus are a great way to review all variables tied to a specific package. The issue is the menu does not show the actual variable names to copy into your init file. Per Jonas Bernoulli (tarsius) on StackOverflow there is a variable to customize this:
(setq custom-unlispify-tag-names nil)
3.5. Optimizations and elisp loading
Prefer newest elisp files
(setq load-prefer-newer t)
Increase the max amount allowed to be read from a process into Emacs.
(setq read-process-output-max (* 1024 1024))
Automatically remove compiled files not needed by current Emacs version.
(setq native-compile-prune-cache t)
3.6. Managing Packages
In 2025, most popular Emacs packages can be installed from the default Emacs Lisp Package Archives GNU ELPA and NonGNU ELPA. Both repositories contain only Free Software, but NonGNU packages do not have their copyright assigned to FSF and cannot be included in mainline Emacs for legal reasons.
These archives are well vetted and can be relatively assumed to be safe and secure.
3.6.1. use-package — Macro for Installing and Configuring Packages
Included with Emacs 29.1 use-package provides an easy way to configure Emacs packages and delay their loading so it does not negatively impact your loading time.
- VC Install – Install from Source Code Repository
The :vc keyword has been added to use-package in Emacs 30. This should make it easy to add packages outside the default archives. This is probably safer than using MELPA since you have to explicitly acknowledge you are installing an external package and verifying the repository source.
3.6.2. Hide minor modes in the mode-line
There are two different packages for hiding or modifying how minor modes are shown on the mode-line.
Both have keyword support in use-package (:delight / :deminish),
and both are included in GNU ELPA. I currently use delight.
(use-package delight :ensure t)
3.7. Useful Functions
3.7.1. File to String
(defun my/file-to-string (filename) "Convert contents of file FILENAME to a string." (string-trim (with-temp-buffer (insert-file-contents filename) (buffer-string))))
3.7.2. Copy Whole Buffer to Clipboard
(defun my/copy-whole-buffer () (interactive) (copy-region-as-kill (point-min) (point-max)) (message "Copied buffer %s to clipboard." (buffer-name)))
3.7.3. SVG Screenshot
Taken from oantolin on reddit, really neat feature.
(defun screenshot () "Take a SVG screenshot of the current frame." (interactive) (let ((filename (make-temp-file (concat "emacs-" (format-time-string "%Y-%m-%dT%H:%M")) nil ".svg" (x-export-frames nil 'svg))))))
3.7.4. Insert Keybinding and Function Name
(defun my/insert-keybind (function) "Insert keybinding for a given FUNCTION. If no keybinding exists just insert the function name." (interactive (help-fns--describe-function-or-command-prompt)) (let ((key (where-is-internal function nil 'first-only))) (insert (if (null key) (format "=%S=" function) (format "*%s* (=%S=)" (key-description key) function)))))
3.7.5. Quick Date Timestamp
(defun my/insert-datestamp () (interactive) (insert (time-stamp-string "%Y-%02m-%02d")))
3.7.6. Reformat string as a variable name
(defun my/format-as-variable (string &optional delim) "Reformat STRING as a variable separated by DELIM. The new string automatically is copied to the kill ring." ;; TODO support camel case. ;; TODO dwim at point. (interactive (list (read-string "String:" (current-kill 0 t)))) (kill-new (replace-regexp-in-string "[[:space:]]+" (or delim "-") (downcase (string-trim string)))) (when (called-interactively-p 'any) (message "\"%s\" copied to kill ring." (current-kill 0 t))) (current-kill 0 t))
4. General Usage
These are settings that improve overall Emacs usage.
4.1. Confirm before Exiting
(setq confirm-kill-emacs #'yes-or-no-p)
4.2. Mouse and Scrolling
Trying out more conservative scrolling options that were recommended
by Marie Katrine Ekeberg. This helps prevent Emacs from violently
reentering the point as frequently. The scroll-margin will make
scrolling start when the point is within x lines of the top/bottom of
the window.
(setq scroll-conservatively 10
scroll-margin 0)
Emacs 29 with pure GTK added a very smooth pixel scrolling feature (what you are used to when scrolling on your touchscreen phone etc.). I wasn't sure if I would like this, but when casually using the touchpad it makes the scrolling much easier to follow. Great for skimming through large text files.
(when (version<= "29" emacs-version) (pixel-scroll-precision-mode))
4.3. Modeline formatting
Improve buffer naming convention when a buffer with a duplicate named buffer is opened.
(require 'uniquify) (setq uniquify-buffer-name-style 'forward)
4.4. Global Keybindings
(global-set-key (kbd "<f12>") #'my/copy-whole-buffer)
4.4.1. Unbind keys
Don't hide the frame
(global-set-key (kbd "C-z") nil) (global-set-key (kbd "C-x C-z") nil)
4.5. Keybinding reminders
When using Emacs there is always the problem of keeping track of the many keybindings used across multiple modes. One solution I recommend is keeping consistent bindings across modes as possible, may modes try to do this by default to varying levels of success.
I tried which-key but I find the output hard to visually parse. I prefer to use the existing help options.
- Start typing a key prefix then type C-h to see all key options.
- C-h m to see all keybindings for current mode.
4.6. Bookmarks
Emacs bookmarks are accessed from in the register keycords C-x r
- C-x r l
- open bookmarks list
- C-x r b
- switch buffer to bookmark
- C-x r m
- save bookmark
(use-package bookmark :hook (bookmark-bmenu-mode . hl-line-mode) :config (setq bookmark-sort-flag 'last-modified) (setq bookmark-save-flag 1))
4.7. WIP ibuffer — Managing buffers
ibuffer is an included package that provides a number of improvements over the standard buffer-menu functions. One piece of this is allowing filtering and grouping of buffers. I have not utilized this very effectively so far, but am investigating it.
(use-package ibuffer :bind (("C-x C-b" . ibuffer)) :config (add-hook 'ibuffer-mode-hook #'hl-line-mode) (setq ibuffer-saved-filter-groups '(("default" ("emacs" (or (name . "^\\*scratch\\*$") (name . "^\\*Messages\\*$") (name . "^\\*Packages\\*$") (name . "^\\*help\\*$") (name . "^\\*info\\*$")))))) (add-hook 'ibuffer-mode-hook (lambda () (ibuffer-switch-to-saved-filter-groups "default"))))
4.8. TODO Windows Placement
This is discussed in detail in the Emacs Manual Window Choice and in the Elisp Manual Displaying Buffers.
I don't feel like I fully comprehend how to use this. Basically I am frustrated with how randomly placed some new windows are (Help, Org Src, etc.) and I'd like those to appear more consistently.
;; (setq display-buffer-alist ;; `(("\\`\\*Async Shell Command\\*\\'" ;; (display-buffer-no-window)) ;; ("\\*Shortdoc .*\\*" ;; (display-buffer-reuse-window display-buffer-in-side-window)) ;; ("\\*Help\\*" ;; display-buffer-pop-up-window ;; (inhibit-same-window . t)) ;; ("\\*Org Src .*\\*" ;; display-buffer-below-selected)))
4.9. Remember History
Track recently opened files.
(require 'recentf) (recentf-mode 1) (setq recentf-max-saved-items 100) (setq recentf-menu-open-all-flag t)
Track minibuffer history.
(savehist-mode 1)
4.10. Repeat-mode — Repeat Commands Quickly
(repeat-mode 1)
4.11. Open File Path at Point
This will automatically check if there is a filepath at point and enter it as the default value, see entry in the emacs manual.
(ffap-bindings)
There is similar functionality for turning URLs into clickable buttons.
4.12. Mini Buffer Enhancements and Completion
4.12.1. Marginalia — Richer Information in Mini Buffer
Marginalia adds additional rich text to the completion sections in the mini buffer (M-x run commands, C-x b switch buffer, C-h f describe function, etc.)
(use-package marginalia :ensure t :init (marginalia-mode))
4.12.2. Vertico — Vertical Completions in Mini-Buffer
Trying out vertico. I need to read through the documentation to better understand what it improves over the built in icomplete framework.
(use-package vertico :ensure t :init (vertico-mode) :config (setq vertico-resize t) (vertico-reverse-mode) (setq read-buffer-completion-ignore-case t) (setq read-file-name-completion-ignore-case t) (add-hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy)) ;; Emacs 28: Hide commands in M-x which do not work in the current mode. ;; Vertico commands are hidden in normal buffers. (when (version<= "28" emacs-version) (setq read-extended-command-predicate #'command-completion-default-include-p))
4.12.3. Consult — Search Multiple Places at Once
Consult is a very powerful package, but I basically use it as a unified file launcher. If I do not know whether I have a file open I use consult to open it quickly without needing to use find-file/recentf/bookmark-menu.
Otherwise I still use normal find-file and switch-to-buffer.
(use-package consult :ensure t :config (global-set-key (kbd "M-z") 'consult-buffer) ; Overwrites zap-to-char (setq consult-preview-key nil) ;; Hide all *special* buffers (add-to-list 'consult-buffer-filter "\\`\\*.*\\*\\'"))
4.12.4. Orderless — Orderless Fuzzy Searching
Match completions regardless of order input. Extremely helpful if you do not entirely remember the order of a command or file name. E.g. is it package-install or install-package entering package install will return the correct result either way.
(use-package orderless :ensure t :config (setq orderless-smart-case nil) (setq completion-styles '(basic flex orderless)) (setq completion-category-overrides '((file (styles basic partial-completion)))))
4.13. Dired
Dired is the built in Emacs directory viewer (dir-ectory ed-itor), like a file explorer. I find Dired one of the more confusing Emacs tools.
Open current directory in dired with C-x . (overrides set-fill-prefix).
(global-set-key (kbd "C-x .") #'(lambda () "Open dired in current directory" (interactive) (dired default-directory)))
(use-package dired :config ;; Thanks to Drew and Nichijou on StackOverflow ;; https://emacs.stackexchange.com/questions/64982/copy-a-file-content-to-clipboard-with-dired (defun my/dired-yank-file-contents () "Kill (copy) file contents to clipboard." (interactive) (let ((buf (find-file-noselect (dired-get-file-for-visit)))) (with-current-buffer buf (kill-new (buffer-substring-no-properties (point-min) (point-max)))) (message "Copied file contents of %S" (file-relative-name (buffer-file-name buf))) (kill-buffer buf))) (define-key dired-mode-map (kbd "Y") #'my/dired-yank-file-contents) (define-key dired-mode-map (kbd "P") #'dired-up-directory) (setq dired-auto-revert-buffer #'dired-directory-changed-p) (setq dired-make-directory-clickable t) (setq dired-recursive-copies 'always) (setq dired-recursive-deletes 'always) ;; Easy dual-pane file manager (setq dired-dwim-target t) (setq dired-free-space nil) (setq dired-listing-switches "-lahG --group-directories-first --time-style=long-iso") (setq dired-guess-shell-alist-user ; those are the suggestions for ! and & in Dired '(("\\.\\(png\\|jpe?g\\|tiff\\)" "xdg-open") ("\\.\\(mp[34]\\|m4a\\|ogg\\|flac\\|webm\\|mkv\\)" "mpv" "xdg-open") (".*" "xdg-open"))) (add-hook 'dired-mode-hook #'dired-hide-details-mode) (add-hook 'dired-mode-hook #'dired-omit-mode) (add-hook 'dired-mode-hook #'hl-line-mode) (require 'dired-aux) (setq dired-vc-rename-file t) (setq dired-create-destination-dirs 'ask))
Allow using 'a' key in dired, this will open the next file/directory and kill the previous Dired buffer. Helpful to avoid creating a bunch of unneeded buffers.
(put 'dired-find-alternate-file 'disabled nil)
4.13.1. Delete to Trash
(setq delete-by-moving-to-trash t)
4.14. Read-Only File View
Enables view mode in all read-only files
(setq view-read-only t)
4.15. Passwords
Currently I've found pass to be a really easy way to manage passwords. You can access those passwords automatically through auth-source.
(require 'auth-source) (auth-source-pass-enable)
If you need to access FTP servers over TRAMP then you should know it cannot retrieve passwords via auth-sources, see tramp#Password handling. You must use a netrc file instead and specify that to ange-ftp:
(customize-set-variable 'ange-ftp-netrc-filename "~/.authinfo.gpg")
4.16. Remote file editing
Don't check for version control over tramp, this slows down tramp.
(setq vc-ignore-dir-regexp (format "\\(%s\\)\\|\\(%s\\)" vc-ignore-dir-regexp tramp-file-name-regexp))
4.17. Compile
(eval-after-load "compile" '(define-key compilation-mode-map (kbd "G") #'compile))
5. Applications
General usage applications I use inside Emacs.
5.1. System Processes
(use-package proced :config (setq proced-auto-update-flag 'visible) ; Emacs 30 supports more the `visible' value (setq proced-enable-color-flag t) ; Emacs 29 (setq proced-auto-update-interval 5) (setq proced-descend t))
5.2. Terminal
Currently trying out eshell instead of bash. I'm excited that it is platform agnostic so I can use it on MS Windows if needed.
(defun eshell-current-directory (&optional directory) "Open eshell current `default-directory' or DIRECTORY." (interactive) (let ((current-dir (or directory default-directory)) (eshell-buffer (or (get-buffer "*eshell*") (eshell)))) (switch-to-buffer eshell-buffer) (eshell/cd current-dir) (eshell-next-prompt) ;; Regenerate prompt to show current directory. ;; Avoid sending any half written input commands (if (eobp) (eshell-send-input nil nil nil) (move-end-of-line nil) (eshell-kill-input) (eshell-send-input nil nil nil) (yank))))
I've bound this to C-x e so whenever I am working on something I can
quickly open a terminal in the current directory. If I don't want to
change directories then I can use switch-to-buffer instead.
(global-set-key (kbd "C-x e") #'eshell-current-directory)
5.2.1. Shell-mode
When using bash I generally use shell-mode. Compilation highlighting in shell-mode.
(add-hook 'shell-mode-hook 'compilation-shell-minor-mode)
5.3. Git
Most of my settings are taken from Prot's configuration. I am still experimenting with VC over magit.
(global-set-key (kbd "C-x v d") #'vc-diff) (global-set-key (kbd "C-x v p") #'vc-dir-root) (global-set-key (kbd "C-x v .") #'(lambda () (interactive) (vc-dir default-directory))) (global-set-key (kbd "C-x v /") #'vc-dir) (global-set-key (kbd "C-x v f") #'vc-pull) (with-eval-after-load 'vc (require 'vc-annotate) (require 'vc-git) (require 'add-log) (require 'log-view) (require 'vc-dir) (define-key vc-dir-mode-map (kbd "d") #'vc-diff) (setq vc-handled-backends '(Git)) ;; This is for editing commit messages. (require 'log-edit) (setq log-edit-confirm 'changed) (setq log-edit-keep-buffer nil) (setq log-edit-require-final-newline t) (setq vc-git-log-edit-summary-target-len 50) (setq vc-git-log-edit-summary-max-len 70) (define-key log-edit-mode-map (kbd "C-c C-a") #'vc-git-log-edit-toggle-amend) (setq vc-git-diff-switches '("--patch-with-stat" "--histogram")) (setq vc-git-log-switches '("--stat")) (setq log-edit-hook '(log-edit-insert-message-template log-edit-insert-changelog log-edit-show-files)))
5.3.1. Git for MS Windows
(add-to-list 'exec-path "C:/Users/thomasingram/AppData/Local/Programs/Git/cmd")
When using git on Windows I use the installer provided by git-scm.com.
The installer provides all the necessary utilities. However I have
found that the ssh_askpass can fail to locate the proper exe file.
Explicitly defining SSHASKPASS should correct that error.
(setenv "SSH_ASKPASS" "c:/Users/thomasingram/AppData/Local/Programs/Git/mingw64/bin/git-askpass.exe")
If you install git with bash then it comes with a number of useful GNU tools. You can use these tools in Emacs by finding them and adding them to your PATH. This can be done in PowerShell with:
setx PATH "%PATH%;C:\Users\thomasingram\AppData\Local\Programs\Git\cmd;C:\Users\thomasingram\AppData\Local\Programs\Git\usr\bin"
I've had some issue with this setting sticking. I got it to work briefly then had issues. This may be a security limitation with my work machine. Adding the program directory to the exec-path in emacs does not seem to work either.
Review PATH in Windows:
$env:PATH -split ';'
5.3.2. Magit
Magit provides an enhanced git interface over the built-in vc-mode. Magit also connects to nearly all regularly used git features so you never need to drop to the commandline. If you like to make lots of changes then stage/commit them afterwards magit makes that process somewhat easier using staging area.
(use-package magit :bind ("C-x g" . magit))
5.4. Calendar and Diary
(use-package calendar :config (setq calendar-week-start-date 1) ; Monday (setq calendar-date-style 'iso) (setq calendar-view-diary-initially-flag t) (setq calendar-mark-holidays-flag t) (setq calendar-mark-diary-entries-flag t) (setq calendar-holidays '((holiday-fixed 1 1 "New Year's Day") (holiday-float 1 1 3 "Martin Luther King Day") (holiday-fixed 2 14 "Valentine's Day") (holiday-fixed 3 17 "St. Patrick's Day") (holiday-float 5 0 2 "Mother's Day") (holiday-float 5 1 -1 "Memorial Day") (holiday-float 6 0 3 "Father's Day") (holiday-fixed 7 4 "Independence Day") (holiday-float 9 1 1 "Labor Day") (holiday-fixed 10 31 "Halloween") (holiday-float 11 4 4 "Thanksgiving") (holiday-easter-etc) (holiday-fixed 12 25 "Christmas") (solar-equinoxes-solstices) (holiday-sexp calendar-daylight-savings-starts (format "Daylight Saving Time Begins %s" (solar-time-string (/ calendar-daylight-savings-starts-time (float 60)) calendar-standard-time-zone-name))) (holiday-sexp calendar-daylight-savings-ends (format "Daylight Saving Time Ends %s" (solar-time-string (/ calendar-daylight-savings-ends-time (float 60)) calendar-daylight-time-zone-name))))) (setq diary-date-forms diary-iso-date-forms) (defalias 'diary-birthday #'diary-anniversary))
5.5. Text Web Browser — Eww
(use-package eww :config (define-key eww-mode-map (kbd "y") #'eww-copy-page-url))
5.6. PDF Viewer
I'm investigating emacs-reader as it seems to make several improvements over pdf-tools. However, I am waiting for the required mupdf version 1.26 to be packaged for Debian.
(pdf-tools-install)
5.7. Email
I really like the concept of email in Emacs. Since it is where I already do all my text editing it makes sense to handle my email as well. I also really like having a local mail store saved on my hard drive using isync. I am still experimenting with Emacs mail clients and trying to find a setup that works for me.
In 2025 the main Emacs email clients are:
- Gnus - Emacs client built into Emacs and used by many of the core Emacs developers. It was originally written as a usenet reader and has some quarks from that. It is pretty complicated but has a detailed info manual.
- mu4e - mail indexer and Emacs mail client reusing features from Gnus. Requires external mail syncing program.
- notmuch - mail indexer and Emacs mail client. Requires external mail syncing program.
- wanderlust - mail client that supports IMAP.
rmail is also built into Emacs but only supports the mbox mail format which is not widely used by mail providers.
5.7.1. General Setup
(setq user-full-name "Thomas Ingram" user-mail-address "thomas@taingram.org")
Configuration for sending emails over SMUT.
(require 'smtpmail) (setq smtpmail-default-smtp-server "smtp.fastmail.com") (setq smtpmail-smtp-server "smtp.fastmail.com") (setq smtpmail-stream-type 'ssl) (setq smtpmail-smtp-service 465) (setq send-mail-function 'smtp-send-it) (setq message-send-mail-function 'smtpmail-send-it) (setq message-signature "Thomas Ingram\nhttps://taingram.org/")
5.7.2. Mail Client — Mu4e
I manually built the latest version of mu4e so I have to add that to my load-path. Debian also provides a pre-built package.
My minor complaint with mu4e is the welcome screen (mu4e-main) is kind of ugly in my opinion.
(use-package mu4e :load-path "/usr/local/share/emacs/site-lisp/mu4e/" :commands mu4e :bind (:map mu4e-view-mode-map ("g" . mu4e-view-refresh) ("G" . mu4e-update-mail-and-index) ("y" . mu4e-copy-thing-at-point) ("o" . mu4e-view-go-to-url) ("a" . mu4e-view-mark-for-refile) ("r" . mu4e-compose-reply) ("R" . mu4e-compose-wide-reply) ("N" . mu4e-view-headers-next-unread) ("P" . mu4e-view-headers-prev-unread) :map mu4e-compose-minor-mode-map ("r" . mu4e-compose-reply) ("R" . mu4e-compose-wide-reply) :map mu4e-headers-mode-map ("g" . mu4e-view-refresh) ("G" . mu4e-update-mail-and-index) ("y" . mu4e-copy-thing-at-point) ("o" . mu4e-view-go-to-url) ("a" . mu4e-view-mark-for-refile) ("r" . mu4e-compose-reply) ("R" . mu4e-compose-wide-reply) ("N" . mu4e-view-headers-next-unread) ("P" . mu4e-view-headers-prev-unread) :map mu4e-main-mode-map ("g" . mu4e-view-refresh) ("G" . mu4e-update-mail-and-index)) :config (set-variable 'read-mail-command 'mu4e) (with-eval-after-load "mm-decode" (add-to-list 'mm-discouraged-alternatives "text/html") (add-to-list 'mm-discouraged-alternatives "text/richtext") (add-to-list 'mm-discouraged-alternatives "multipart/related")) (add-to-list 'mu4e-bookmarks `(:name "Inbox" :key ?i :query "maildir:/Inbox")) (setq mu4e-sent-folder "/Sent") (setq mu4e-refile-folder "/Archive") (setq mu4e-drafts-folder "/Drafts") (setq mu4e-trash-folder "/Trash") (setq mu4e-attachment-dir "/tmp/") (setq mu4e-view-fields '(:subject :date :from-or-to :cc :mailing-list :maildir :flags)) (setq mu4e-get-mail-command "mbsync thomas@taingram.org") ;; Prevent mbsync "Maildir error: duplicate UID" (setq mu4e-change-filenames-when-moving t) (setq message-kill-buffer-on-exit t) (setq mu4e-use-fancy-chars t) (setq mail-user-agent 'mu4e-user-agent))
5.8. Music
I've been a longtime user of the Music Player Daemon (MPD). I generally used ncmpcpp to control it, although I find myself wanting an easy way to control music from Emacs. Ideally an easy way to add/remove songs from the queue using a dired-like view.
I previously tried the included mpd client included with Emacs mpc.el. I disliked the rhythmbox-inspired UI, poor playlist support, and multiple windows. I tend to dislike any Emacs package that starts messing with my window setup unless absolutely necessary.
I was thinking about hacking it to make a more dired-like UI, then I discovered someone else already had the same idea. mpdired is a client written from scratch, so there no code-reuse from mpc.el. It basically works exactly how I was hoping. I just wish it was a little more interactive so I'm hoping to add some enhancements.
My fork can be found on sourcehut git.sr.ht/~taingram/mpdired/
(use-package mpdired :commands (mpdired) :vc (:url "https://git.sr.ht/~taingram/mpdired" :rev :newest) :hook (mpdired-mode . hl-line-mode) :bind (:map mpdired-mode-map ("b" . mpdired-toggle-view)) :config (setq mpdired-highlight-progress nil))
I am also comparing mpdired with the more feature rich emms package. The downside of the emms package is it is not completely integrated with mpd. It can be used to play ANY type of media in a playlist which is really neat.
This setup works okay with mpd with some caveats. I've noticed the
clearing the EMMS playlist does not clear playlist in mpd. In order
to use emms-browser you must occasionally dump your MPD song database
into EMMS. Run emms-player-mpd-music-directory to do that.
(use-package emms :ensure t :config (require 'emms-player-mpd) (setq emms-player-mpd-server-name "localhost") (setq emms-player-mpd-server-port "6600") (add-to-list 'emms-player-list 'emms-player-mpd) (add-to-list 'emms-info-functions 'emms-info-mpd) (emms-player-mpd-connect) (setq emms-player-mpd-sync-playlist t) (setq emms-player-mpd-music-directory "~/Music/") (require 'emms-browser))
6. Editing Text
Configuration and packages that are useful wherever text is edited inside Emacs.
6.1. Delete trailing whitespace
(add-hook 'before-save-hook #'delete-trailing-whitespace)
6.2. Allow overwriting of selected text
(require 'delsel) (delete-selection-mode 1)
6.3. Improve handling long lines
so-long-mode is a new mode in 27.1 that trys to improve Emacs's longstanding
issues with handling long lines.
(when (version< "27" emacs-version) (global-so-long-mode t))
6.4. Spell Checking
Emacs does not provide internal spellchecking but relies on external programs. The two most popular options are:
Aspell is generally faster and returns more results for English. Hunspell provides better spellchecking for other languages and is more widely used in other software (e.g. LibreOffice, Firefox, Google Chrome, and MacOS). On GNU/Linux either of these should be available from your distros package manager (or likely installed already).
Within Emacs there are two main ways to invoke the spellchecker invoke ispell
manually check a buffer or region for spelling errors, or enable flyspell-mode
to do so automatically like a word processor.
Set default dictionary to your desired language.
(setq ispell-local-dictionary "american")
Enable flyspell globally in all text and programming modes:
(use-package flyspell :delight :config (add-hook 'text-mode-hook #'flyspell-mode) (add-hook 'prog-mode-hook #'flyspell-prog-mode))
flyspell-prog-mode will only check spelling in comments and strings.
6.4.1. MS Windows
Aspell has not released a version for Windows since 2002, and in my experience I've found Hunspell to be easier.
- Download Hunspell from ezwinports maintained by Eli Zaretskii.
- Extract the hunspell folder and put it wherever you'd like.
- Add the following to your init file:
(add-to-list 'exec-path "C:/Users/thomasingram/OneDrive - oakland.edu/Apps/hunspell-1.3.2-3/bin") (setq ispell-program-name (locate-file "hunspell" exec-path exec-suffixes 'file-executable-p))
After that you should be all set to use spellchecking in Emacs
For further instructions see this guide by djc on the help-gnu-emacs@gnu.org mailing list. The guide contains some additional steps on setting up multiple dictionaries which is of no use to me as a stereotypical monolingual American.
6.5. Word Wrap
Disable fill-paragraph when visual-line-mode enabled (I have a
habit of using M-q it without thinking).
(define-key visual-line-mode-map [remap fill-paragraph] 'ignore)
6.5.1. Wrap at fill column
This package visually warps likes at the fill-column, so it looks like they are wrapped at a reasonable length. Nice on occasion, but not great for writing in Org because SRC blocks also get wrapped.
(use-package visual-fill-column)
6.6. TODO Electric Pair
6.7. Abbreviations
abbrev-mode is a built in minor mode that provides a convent way to expand abbreviations as you are writing. Abbreviations are expanded when a space or punctuation is typed after completing a word. For example you could have gv expand into government.
gv → government
Abbreviations can also preserve capitalization in useful ways:
Gv → Government
GV → GOVERNMENT
Capitalization works differently if your abbreviation expands to multiple words:
Gdp → Gross domestic product
GDP → Gross Domestic Product
By default abbrev commands can be accessed through C-x a
C-x a gtake a word and define a global abbreviation for it.C-x a ltake a word and define a local (mode specific) abbreviation.C-x a i gdefine the word at point as a global abbreviation and then expand it.C-x a i lsames as above for a mode specific abbreviation.
Additional useful functions:
define-global-abbrev- define both the abbreviation and expansion without pulling from the buffer.
define-mode-abbrev- same as above for mode specific abbrev.
list-abbrevs- List all defined abbrevs. Can edit these directly
and reload with
C-c C-c. edit-abbrevs- Functionally same as
list-abbrevsbut jumps you to mode specific definitions.
Abbreviations are automatically expanded when adding a space or
punctuation. They can be manually expanded with C-x a e (this works
even in buffers without abbrev-mode enabled).
Expansions can be escaped by typing C-q before typing your
space/punctuation. Typing "G D P C-q ," would result in: GDP,
Alternatively if you need to prefix or suffix an abbrev you can note
the end of the prefix and the start off the suffix with M-'
anit (M-') gv (M-') ental → antigovernmentental
Abbrev can automatically remind you when you forget to use
abbreviations by enabling abbrev-suggest. You can get a summary of
how often abbrev-suggest is showing with the
abbrev-suggest-show-report command.
(setq abbrev-suggest 't) (setq abbrev-suggest-hint-threshold 2)
By default Emacs prompts you to save the abbrev file before closing,
this can be done automatically in the background by setting
save-abbrevs
(setq save-abbrevs 'silently)
Enable abbrev-mode in the modes you wish to use it:
(add-hook 'org-mode-hook #'abbrev-mode) (add-hook 'prog-mode-hook #'abbrev-mode)
6.7.1. Dynamic Abbreviation
Dynamic abbreviations (dabbrev) allow for automatic expansion of words based on the buffer contents. This is useful when you are expanding to a word in specific buffer that you may not use again (e.g. a variable name).
- M-/
- Expand word at point by searching backwards in the buffer for a match.
- C-M-/
- Expand the word at point by searching forward in the buffer.
6.8. Non-English Languages
6.8.1. French
If you are using a non-French keyboard then French accents can be entered by prefixing or postfixing an accent character. Emacs can automatically combine this into the correct accented character.
6.8.2. Japanese 日本語
Occasionally I need to type Japanese to reference to video games, wood block printing, stationary, or Japanese carpentry. Emacs provides a lot of great functionality for writing Japanese (日本語). See: Using Emacs and org-mode with Japanese Text (archive)
- Kanji-mode
Kanji-mode is a really cool little package that gives you:
- Stroke order (
M-s M-o) - Kanji to hiragana (
M-s M-h) - Kanji to romanji (
M-s M-h)
- Stroke order (
6.9. Open Data Files in Read-Only View
This can be useful to avoid accidentally editing a large CSV. Normally I just want to review the raw data and not make any changes.
(add-to-list 'auto-mode-alist
'("\\.csv\\'" . (lambda ()
(text-mode)
(view-mode 1))))
7. Programming Modes
(use-package prog-mode :hook ((prog-mode . show-paren-mode) (prog-mode . column-number-mode)))
New feature Emacs 28.
(setq next-error-message-highlight 't)
7.1. Manage Projects
project.el is included with Emacs so we just need to enable it. See
the default keybindings under the C-x p prefix. Try C-x p C-h to see
a full list.
By default projects are identified by being a directory with version
control (e.g. git). Additional files can be used as a project
identifier by customizing project-vc-extra-root-markers.
(use-package project :config (setq project-buffers-viewer 'project-list-buffers-ibuffer))
7.2. Interactive Development Features
7.2.1. Eglot —Language Server Protocol (LSP)
LSP is a recently developed standard communication protocol that allows development tools (code completion, documentation retrieval on hover, lookup definition, and linting/diagnostics). The protocol was originally developed by Microsoft for their Visual Studio Code editor.
There are two competing Emacs plugins
While lsp-mode has a larger development community and is more feature rich, eglot is simpler and included in GNU ELPA.
(use-package eglot :ensure t)
7.2.2. Corfu —Drop down auto-completion support
I am trying to replace company-mode with corfu. Daniel Mendler's packages have been extremely impressive, although the small packages can be a bit overwhelming when you are initially getting started.
(use-package corfu :ensure t ;; Optional customizations ;; :custom ;; (corfu-cycle t) ;; Enable cycling for `corfu-next/previous' ;; (corfu-quit-at-boundary nil) ;; Never quit at completion boundary ;; (corfu-quit-no-match nil) ;; Never quit, even if there is no match ;; (corfu-preview-current nil) ;; Disable current candidate preview ;; (corfu-preselect 'prompt) ;; Preselect the prompt ;; (corfu-on-exact-match nil) ;; Configure handling of exact matches :hook ((prog-mode . corfu-mode) (shell-mode . corfu-mode) (eshell-mode . corfu-mode)) ;; Recommended: Enable Corfu globally. This is recommended since Dabbrev can ;; be used globally (M-/). See also the customization variable ;; `global-corfu-modes' to exclude certain modes. ;; :init ;; (global-corfu-mode) )
7.2.3. Flymake — Error Checking in Buffer
(use-package flymake :bind (:map prog-mode-map ("M-n" . flymake-goto-next-error) ("M-p" . flymake-goto-prev-error)))
7.2.4. auto-insert — Auto Insert Text in New Files
See Emacs Autotype manual section autotype#Autoinserting. When open a new file Emacs can automatically insert a basic skeleton of header text, include standard libraries, main function etcetera.
(auto-insert-mode)
7.2.5. Tempo — Code Templates / Snippets
I have recently removed yasnippets from my config as I rarely used the snippets and often forgot the keywords. When I started using yasnippets I downloaded a repo of premade snippet definitions so that meant I had a lot of stuff I never used and often triggered accidentally. I have started porting my few snippets to tempo.el which is built into Emacs.
(require 'tempo) (setq tempo-interactive t) ; Enable interactive prompts etc
Tempo is a really cool package built into Emacs that is not well documented and does not appear to have a lot of users. Most people seem to use yasnippets instead.
A basic template definition looks like this:
(tempo-define-template "insert-lambda" '("(lambda (" (p "Arguments: ") ")" n> p ")" n) "lambda" "Insert a lambda function.")
For every tempo template defined there is an interactive function
automatically generated named "tempo-template" + "your-template-name".
So you can run M-x tempo-template-insert-lambda and it will insert
the template into your current buffer. This is really nice as since I
can use vertico to look-up my templates quickly.
If you want automatic expansion of the keywords like yasnippets that can be enabled by calling the function in an abbrev definition:
(define-abbrev emacs-lisp-mode-abbrev-table "lambda" "" 'tempo-template-insert-lambda)
7.2.6. Expand and collapse functions
Disabling this for now I do not currently use it and there are other options in Emacs to explore.
Hideshow is a minor mode for hiding and showing contents of functions and comment blocks.
;; (setq hs-hide-comments-when-hiding-all nil) ;; (setq hs-isearch-open t) ;; Backtab is equivalent to shift+tab ;; (define-key hs-minor-mode-map (kbd "<backtab>") 'hs-toggle-hiding) ;; (add-hook 'prog-mode-hook #'hs-minor-mode)
- TODO Replace with outline-mode
Stefan Monnier's talk at Emacs Conf convinced me to try using outline-mode instead of hideshow.
7.3. Emacs Lisp
(use-package emacs-lisp-mode :bind (:map emacs-lisp-mode-map ("C-c C-r" . eval-region) ("C-c C-d" . eval-defun) ("C-c C-b" . eval-buffer) ("C-c C-c" . emacs-lisp-byte-compile) ("C-c C-l" . emacs-lisp-byte-compile-and-load)) :hook ((emacs-lisp-mode . flymake-mode)))
7.3.1. Paredit
Paredit is a really cool way to do structural editing on s-expressions. They keybindings can be a little confusing but it is really helpful to learn and use.
(use-package paredit :ensure t :delight :hook ((emacs-lisp-mode lisp-mode scheme-mode) . paredit-mode))
7.4. Scheme / Guile
(use-package scheme-mode :hook ((scheme-mode . geiser-mode)) :bind (:map geiser-mode-map ("C-c C-d" . geiser-doc-symbol-at-point) ("C-c C-i" . geiser-doc-look-up-manual)))
7.4.1. Geiser — Scheme REPL
(use-package geiser :ensure nil :bind (:map geiser-repl-mode-map ("C-c C-e" . comint-show-maximum-output)))
7.5. Shell
(add-hook 'sh-mode-hook 'flymake-mode)
7.6. PowerShell
(use-package powershell :ensure t :config (add-hook 'powershell-mode-hook #'subword-mode) (add-hook 'powershell-mode-hook (lambda () (setq indent-tabs-mode nil) (setq powershell-indent-offset 4))))
7.7. SQL
(use-package sql :config (add-hook 'sql-mode-hook (lambda () (setq indent-tabs-mode nil))))
7.8. C
(use-package c-mode :bind (:map c-mode-map ("C-c c" . compile) ("C-c C-c" . recompile) ("C-c g" . gdb) ("C-c C-r" . gdb-run)) :hook ((c-mode . electric-pair-mode) (c-mode . flymake-mode)) :config (setq c-block-comment-prefix "* "))
7.9. Go
Note that go-mode is an external package.
(use-package go-mode :ensure nil :bind (:map go-mode-map ("C-c RET" . compile) ("C-c c" . compile) ("C-c C-c" . recompile) ("C-c d" . godoc) ("C-c f" . gofmt) ("C-c g" . gdb) ("C-c C-g" . gdb-run)) :config (defun my/go-mode-set-local () (set-fill-column 80) (set (make-local-variable 'compile-command) "go build -v ")) ;; Disables links to the web documentation (setq-default eglot-workspace-configuration '((:gopls . ((linksInHover . :json-false))))) :hook ((go-mode . my/go-mode-set-local) (go-mode . subword-mode) (go-mode . electric-pair-mode) (before-save . gofmt-before-save)))
7.10. JavaScript
See my post for setting up a JavaScript LSP server.
(use-package js-mode :hook ((js-mode . subword-mode) (js-mode . electric-pair-mode) (js-mode . eglot-ensure) (js-mode . completion-preview-mode))) (define-auto-insert 'js-mode '(nil "// Copyright " (format-time-string "%Y") " " (progn user-full-name) \n \n "'use strict';" \n _))
7.11. Web-Mode
For administration of our Slate CRM I frequently need to edit large amounts of mixed HTML, CSS, and JavaScript. Due to the structure of Slate Portals this is difficult to avoid as I would prefer to break things out separately.
(use-package web-mode :ensure t :config (add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode)) (setq-default web-mode-engine "django") (setq-default web-mode-markup-indent-offset 1) (setq-default web-mode-css-indent-offset 2) (setq-default web-mode-code-indent-offset 4) (setq web-mode-enable-current-column-highlight t) (add-hook 'web-mode-hook (lambda () (setq indent-tabs-mode nil))) ;; Use // comments for JavaScript (add-to-list 'web-mode-comment-formats '("javascript" . "//")))
8. Writing Modes
8.1. Org mode
(use-package org :bind (("C-x c" . org-capture) ("C-x t" . tai-org-capture-todo) :map org-mode-map ("C-c ." . org-timestamp-inactive) ("C-c !" . org-timestamp) :map Info-mode-map ("C-c C-l" . org-store-link)) :hook ((org-mode . auto-fill-mode)) :config ;; Org src evaluation langauges (org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t) (shell . t) (latex . t))) (require 'org-protocol) ;; Templates (e.g. <s expands to #+begin_src) (require 'org-tempo) (tempo-define-template "org-elisp-src-block" '("#+begin_src emacs-lisp" n p n "#+end_src" n) "<el" "Insert an Emacs Lisp source code block template") ;; Alternative tag abbreviation (tempo-add-tag "<es" #'tempo-template-org-elisp-src-block) ;; Font style tweaks (set-face-attribute 'org-priority nil :inherit '(font-lock-comment-face default) :weight 'normal) (set-face-attribute 'org-ellipsis nil :inherit '(font-lock-comment-face default) :weight 'normal) ;; Extend line around source bocks (set-face-attribute 'org-block-begin-line nil :extend t) (set-face-attribute 'org-block-end-line nil :extend t) (setq org-babel-default-header-args:emacs-lisp '((:lexical . "yes"))) (defun tai-org-capture-todo () (interactive) (org-capture nil "t")) (require 'ox-latex) (add-to-list 'org-latex-classes '(("apa6" "\\documentclass[12pt]{apa6}" ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}") ("\\paragraph{%s}" . "\\paragraph*{%s}") ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))) (add-to-list 'org-latex-classes '("apa7" "\\documentclass[stu, 12pt]{apa7}" ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}") ("\\paragraph{%s}" . "\\paragraph*{%s}") ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))) (setq org-latex-title-command "\\maketitle") ;; (setq org-latex-title-command "\\begin{center} ;; %s \\hfill %D ;; \\smallskip ;; \\hrule ;; \\bigskip ;; {\\LARGE \\textbf{\\MakeUppercase{%t}}\\par} ;; \\smallskip ;; %a ;; \\end{center}") :custom ;; Visuals (org-ellipsis "⤵") (org-hide-leading-stars t) ;; (org-startup-indented t) ;; (org-adapt-indentation 'headline-data) (org-hide-emphasis-markers nil) ;; Push M-RET to bottom of section, except when inserting new list items (org-M-RET-may-split-line '((headline . nil) (item . t) (table . nil))) ;; These settings make C-c C-j org-goto much quicker when using a ;; completion package like vertico. (org-goto-interface 'outline-path-completion) (org-outline-path-complete-in-steps nil) (org-src-window-setup 'current-window) ;; Prevent org-capture from creating unnecessary bookmarks (org-bookmark-names-plist '(:last-capture "org-capture-last-stored")) (org-capture-templates `(("t" "Todo" entry (file+headline "~/todo.org" "General Goals and Tasks") "* TODO %^{TODO}\n%u\n\n%a%?") ("e" "Emacs Tweaks" entry (file+headline "~/todo.org" "Emacs Configuring") "* TODO %^{Emacs TODO}\n%u\n%?") ("w" "Writing Idea" entry (file+headline "~/Documents/taingram.org/todo.org" "Blogging") "* IDEA %^{Writing Idea}\n%u\n") ("i" "Idea" entry (file+headline "~/todo.org" "Project Idea") "* IDEA %^{Project Idea}\n%u\n") ("j" "Journal" entry (file+headline "~/Documents/me.org" ,(substring (current-time-string) -4 nil)) "* %u %^{Entry title}\n %?\n") ("l" "Interesting Links" entry (file "~/Documents/taingram.org/org/interesting-links.org") "* %l\n%u" :prepend t) ;; Trying to get org-protocol to work (org capture) ("p" "Protocol" entry (file+headline ,(concat org-directory "notes.org") "Inbox") "* %^{Title}\nSource: %u, %c\n #+BEGIN_QUOTE\n%i\n#+END_QUOTE\n\n\n%?") ("L" "Protocol Link" entry (file+headline ,(concat org-directory "notes.org") "Inbox") "* %? [[%:link][%:description]] \nCaptured On: %U"))) :config (add-hook 'org-mode-hook (lambda () (setq-local electric-pair-inhibit-predicate (lambda (c) (char-equal c ?\<))))))
8.1.1. Org Agenda
Org-agenda is really just an alternative way to view and manage all your org TODO tasks. It is definitely a little messy to setup if you want to customize it, but the functionality is all there and built-in.
I am trying to use it to manage ongoing projects so I don't loose track of what I'm currently working. I can easily distracted. This is also to encourage me to consolidate the and many paper notes I have into one place if the task cannot be finished immediately.
The org-agenda-prefix-format and org-agenda-prefix-format allow you customize how the org-agenda-todo-list is displayed.
(use-package org-agenda :bind (("C-x C-a" . org-agenda) :map org-agenda-mode-map ("o" . org-agenda-open-link) ("C" . org-capture) ("C-<return>" . org-agenda-tree-to-indirect-buffer)) :custom ;; Org agenda setup (org-agenda-files '("~/todo.org" "~/Documents/taingram.org/todo.org")) (org-agenda-include-diary t) (org-agenda-todo-list-sublevels nil) ;; Hide TODO/DONE from agenda views ;; (org-agenda-todo-keyword-format "") ;; Hide unnecessary time info (org-agenda-time-grid '((daily today require-timed) () " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")) (org-agenda-show-current-time-in-grid nil) (org-agenda-custom-commands '(("h" "General Hobby Tasks" ((agenda "" ((org-agenda-span 1) (org-agenda-overriding-header "Energy Priortiziation\n 1. Coding\n 2. French\n 3. Drawing\n 4. Writing\n"))) (todo "PROG" ((org-agenda-overriding-header "Tasks In Progress: PROG"))) (tags-todo "-PROJECT-IDEA-HOLD/TODO|+LEVEL=2+PROJECT/TODO" ((org-agenda-overriding-header "Tasks: TODO"))) (tags-todo "-PROJECT-IDEA/HOLD|+LEVEL=2+PROJECT/HOLD" ((org-agenda-overriding-header "Tasks on Hold: HOLD")))) ((org-agenda-sorting-strategy '(priority-down tag-up)))) ("w" "Writing Tasks and Ideas" ((tags-todo "+WRITING/PROG" ((org-agenda-overriding-header "Writing Tasks In Progress"))) (tags-todo "+WRITING/!-PROG" ((org-agenda-overriding-header "Writing To-do & Ideas"))))) ("i" "Project and Writing Ideas" ((tags-todo "-DREAM+TODO=\"IDEA\"" ((org-agenda-overriding-header "Project Ideas: IDEA"))) (tags-todo "+DREAM+TODO=\"IDEA\"" ((org-agenda-overriding-header "Dream Project Ideas:"))))))))
8.1.2. Auto Tangle
This is useful for to avoid forgetting to tangle my init.org file.
(use-package org-auto-tangle :ensure t :delight :config (add-hook 'org-mode-hook 'org-auto-tangle-mode))
8.1.3. Blogging
Load my htmlize and blog's configuration file. For more information
on blogging with Org-mode see: Building a Emacs Org-Mode Blog
(use-package htmlize :ensure t) (use-package org-publish-rss :load-path "~/.config/emacs/my-lisp/org-publish-rss/" :config (setq org-publish-rss-publish-immediately t)) (load "~/Documents/taingram.org/publish.el")
8.2. Markdown
I personally am not a huge fan of markdown, org mode's syntax just makes much more sense to me. However it is unavoidable.
(use-package markdown-mode :ensure t)
8.3. LaTeX
Old setup, I haven't used LaTeX since I graduated college and it is unlikely that I'll need to use it any time soon…
(use-package tex :ensure nil ; auctex :mode ("\\.tex\\'" . latex-mode) :config (defun my/latex-compile () "My compile latex function" (interactive) (save-buffer) (TeX-command "LaTeX" 'TeX-master-file)) (setq TeX-command-default 'LaTeX) :bind (:map TeX-mode-map ("C-c _" . "\\textunderscore ")) :hook ((TeX-mode . auto-fill-mode)))
9. See Also
Other interesting literate configuration files that inspired me.
Footnotes:
How Emacs changed my life by Matz Yukihori the creator of Ruby. The talk explains how access to Emacs's source code directly inspired him in the development of Ruby.
Comments
Email comments to comment@taingram.org.