From 745c56f7fc5373f0ba78b550a43de97482ba5c9c Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Thu, 4 Aug 2016 00:45:51 +0200 Subject: Convert Emacs config to literate org document --- emacs/.emacs.d/init.org | 575 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 575 insertions(+) create mode 100644 emacs/.emacs.d/init.org (limited to 'emacs/.emacs.d/init.org') diff --git a/emacs/.emacs.d/init.org b/emacs/.emacs.d/init.org new file mode 100644 index 0000000..a5a7ee5 --- /dev/null +++ b/emacs/.emacs.d/init.org @@ -0,0 +1,575 @@ +#+TITLE: Tom-Emacs Interface +#+STARTUP: showall + +This is my personal Emacs configuration. The name was inspired by +"Ghost in the Shell 2: Man-Machine Interface and Ryan Rix's "Complete +Computing Environment". + +To start off, first I need to enable lexical binding. + +#+BEGIN_SRC emacs-lisp :padline no + ;; -*- lexical-binding: t; -*- +#+END_SRC + +* Package configuration + + Require package.el since I immediately start using its variables and + functions anyway, no need to delay loading. + + #+BEGIN_SRC emacs-lisp + (require 'package) + #+END_SRC + + Add the MELPA and org package archives because I like living on the + bleeding edge. This should be done both at run-time and compile-time + so I can install packages at compile time. + + #+BEGIN_SRC emacs-lisp + (eval-and-compile + (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) + (add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/"))) + #+END_SRC + + Initialize package.el so that packages can be loaded and used. This + also needs to be done at both run-time and compile-time so packages + can be installed at compile-time. + + #+BEGIN_SRC emacs-lisp + (eval-and-compile (package-initialize)) + #+END_SRC + + Refresh the package contents so packages can be installed from all + configured archives. Don't do this at run-time because it slows down + the process too much. + + #+BEGIN_SRC emacs-lisp + (eval-when-compile (package-refresh-contents)) + #+END_SRC + + This macro is inspired by use-package, but I want to maintain some + control of the syntax I use to configure my settings. + + #+BEGIN_SRC emacs-lisp + (defmacro ensure-library (library &rest args) + "Make sure LIBRARY is installed. + + ARGS should be a plist which may contain one of the following options: + + - :package + + Specify which package should actually be installed to ensure + the library named in LIBRARY exists. + + - :path + + Specify a path to add to the load path to be able to load this + package." + (declare (indent 1)) + (let ((library-symbol (cl-gensym)) + (package-symbol (cl-gensym)) + (path-symbol (cl-gensym)) + (package (or (plist-get args :package) library)) + (path (plist-get args :path))) + `(progn + (eval-and-compile + (let ((,path-symbol ,path)) + (if ,path-symbol + (add-to-list 'load-path + (if (file-name-absolute-p ,path-symbol) + ,path-symbol + (concat user-emacs-directory ,path-symbol)))))) + (eval-when-compile + (let ((,library-symbol ',library) + (,package-symbol ',package)) + (unless (require ,library-symbol nil :noerror) + (package-install ,package-symbol) + (require ,library-symbol))))))) + #+END_SRC + +* Helper functions + + I have noticed that I refer to the combination of + =user-emacs-directory= and "data/" a lot, so I wrote this function + to make referencing it cleaner. Also useful if I ever want to move + my data directory. + + #+BEGIN_SRC emacs-lisp + (defun oni:data-location (file-name) + "Return the location of FILE-NAME within my data directory. + This is currently the data directory under the + `user-emacs-directory'." + (concat user-emacs-directory "data/" file-name)) + #+END_SRC + + I also wrote a test for it. + + #+BEGIN_SRC emacs-lisp + (with-eval-after-load 'ert + (ert-deftest oni:data-location () + "Test that `oni:data-location' returns the correct locations." + (should (string= "~/.emacs.d/data/backup-files/" + (oni:data-location "backup-files/"))) + (should (string= "~/.emacs.d/data/auto-save-files/" + (oni:data-location "auto-save-files/"))) + (should (string= "~/.emacs.d/data/auto-save-list/.saves-" + (oni:data-location "auto-save-list/.saves-"))))) + #+END_SRC + +* Backups + + I don't like having every directory filled with "filename~" + files. So instead of saving backup files to the same directory, save + them to a special one instead. + + #+BEGIN_SRC emacs-lisp + (setq backup-directory-alist `((".*" . ,(oni:data-location "backup-files/")))) + #+END_SRC + +* Auto saves + + I prefer to keep all autosave files in a single directory so they + don't clog up my filesystem so much. Usually these files get + deleted, but sometimes they don't, and I don't think they look + pretty. Add it to the end of the list because the default value + stores auto-saves for remote files in /tmp, which is fine by me. + + #+BEGIN_SRC emacs-lisp + (add-to-list 'auto-save-file-name-transforms + `(".*" ,(oni:data-location "auto-save-files/") t) :append) + #+END_SRC + + Place the files which contain the auto save files in a similar + directory. + + #+BEGIN_SRC emacs-lisp + (setq auto-save-list-file-prefix (oni:data-location "auto-save-list/.saves-")) + #+END_SRC + +* Tabs + + Generally I prefer using spaces over tabs. Especially for lisp-like + languages. + + #+BEGIN_SRC emacs-lisp + (setq-default indent-tabs-mode nil) + #+END_SRC + + A tab-width of 8 is too wide for me, and 2 is too narrow. 4 is just + right. + + #+BEGIN_SRC emacs-lisp + (setq-default tab-width 4) + #+END_SRC + +* Font + + Set the default font to a more pleasing one, in my opinion, with a + better size as well. + + #+BEGIN_SRC emacs-lisp + (add-to-list 'default-frame-alist '(font . "Fantasque Sans Mono-13")) + #+END_SRC + +* Menu bar + + I don't use the menu bar, so it just takes up space. + + #+BEGIN_SRC emacs-lisp + (menu-bar-mode -1) + #+END_SRC + +* Tool bar + + I don't use the tool bar, so it just takes up space. + + #+BEGIN_SRC emacs-lisp + (tool-bar-mode -1) + #+END_SRC + +* Scroll bar + + I don't use the scroll bar to either navigate my buffers or see + whereabouts I am, so they just take up space. + + #+BEGIN_SRC emacs-lisp + (scroll-bar-mode -1) + #+END_SRC + +* Whitespace + + I hate it when trailing whitespace is left around a file. I've been + using this for years, and apart from having some trouble working + with people who don't pay attention to it, it has worked flawlessly. + + #+BEGIN_SRC emacs-lisp + (ensure-library destroy-trailing-whitespace + :path "vendor-lisp/destroy-trailing-whitespace") + (require 'destroy-trailing-whitespace) + (global-destroy-trailing-whitespace-mode) + #+END_SRC + + Having a final newline at the end of the file is always a good + idea. Some programs just don't work without it and others produce + some strange results. Github diffs are an example. + + #+BEGIN_SRC emacs-lisp + (setq require-final-newline t) + #+END_SRC + +* Theme + + I am trying out Zerodark lately. + + #+BEGIN_SRC emacs-lisp + (ensure-library zerodark-theme) + (load-theme 'zerodark :no-confirm) + #+END_SRC + +* Ivy + + Ivy is a completing read implementation that offers choises + vertically. I'm surprised how much I like it. I've tried Swiper + before and I didn't like that so much. + + #+BEGIN_SRC emacs-lisp + (ensure-library ivy) + #+END_SRC + + Also install the =flx= package to allow ivy to use fuzzy matching. + + #+BEGIN_SRC emacs-lisp + (ensure-library flx) + #+END_SRC + + Since I immediately use and enable Ivy, there's no need to autoload + it, so require it to keep the byte-compiler quiet. + + #+BEGIN_SRC emacs-lisp + (require 'ivy) + #+END_SRC + + Enable fuzzy matching in Ivy. + + #+BEGIN_SRC emacs-lisp + (setq ivy-re-builders-alist '((t . ivy--regex-fuzzy)) + ivy-initial-inputs-alist nil) + #+END_SRC + + Enable Ivy. + + #+BEGIN_SRC emacs-lisp + (ivy-mode) + #+END_SRC + +* Counsel + + Counsel is a group of functions that use Ivy to specialize on + certain built-in commands, such as M-x. + + #+BEGIN_SRC emacs-lisp + (ensure-library counsel) + #+END_SRC + + Since I enable Counsel mode immediately, there's no point in leaving + it to be autoloaded. Requiring it keeps the byte-compiler happy. + + #+BEGIN_SRC emacs-lisp + (require 'counsel) + #+END_SRC + + Enable Counsel. + + #+BEGIN_SRC emacs-lisp + (counsel-mode) + #+END_SRC + +* Bookmarks + + Save bookmarks in my data directory so my =user-emacs-directory= is less cluttered. + + #+BEGIN_SRC emacs-lisp + (eval-when-compile (require 'bookmark)) + (setq bookmark-default-file (oni:data-location "bookmarks")) + #+END_SRC + +* Personal info + + Set some personal info for, for example, Gnus to use. + + #+BEGIN_SRC emacs-lisp + (setq user-full-name "Tom Willemse" + user-mail-address "tom@ryuslash.org") + #+END_SRC + +* Minor modes + +** Paredit + + Paredit is an awesome minor-mode to have when you write in any + lisp-like languages. It can feel rather strict and uncomfortable at + first, but once you get the hang of using it, you won't want to + live without it. + + #+BEGIN_SRC emacs-lisp + (ensure-library paredit) + #+END_SRC + +** Electric indent mode + + By default `electric-indent-mode' is enabled globally, but I prefer + to enable it locally where I need it. + + #+BEGIN_SRC emacs-lisp + (electric-indent-mode -1) + #+END_SRC + + Since Emacs 24 `electric-indent-mode' switches the behavior of the + C-j and RET keys. I prefer the original situation because my + muscle-memory still remembers to use C-j for newline-and-indent + behaviour. + + #+BEGIN_SRC emacs-lisp + (defun oni:switch-newline-keys () + "Switch the C-j and RET keys in the local buffer." + (if electric-indent-mode + (progn + (local-set-key (kbd "C-j") 'newline) + (local-set-key (kbd "RET") 'electric-newline-and-maybe-indent)) + (local-unset-key (kbd "C-j")) + (local-unset-key (kbd "RET")))) + + (add-hook 'electric-indent-local-mode-hook #'oni:switch-newline-keys) + #+END_SRC + +* Major modes + +** Emacs lisp mode + + Enable paredit mode. + + #+BEGIN_SRC emacs-lisp + (add-hook 'emacs-lisp-mode-hook 'paredit-mode) + #+END_SRC + +** Scheme mode + + Enable paredit mode. + + #+BEGIN_SRC emacs-lisp + (add-hook 'scheme-mode-hook 'paredit-mode) + #+END_SRC + + Add scsh to the list of known interpreters for scheme mode. This + way shell-scripts that don't have a file extension but specify scsh + as the interpreter are opened in scheme mode. + + #+BEGIN_SRC emacs-lisp + (add-to-list 'interpreter-mode-alist '("scsh" . scheme-mode)) + #+END_SRC + +** Inferior Emacs lisp mode (ielm) + + Enable paredit mode. + + #+BEGIN_SRC emacs-lisp + (add-hook 'inferior-emacs-lisp-mode-hook 'paredit-mode) + #+END_SRC + +** Mbsync configuration mode + + I wrote a simple major-mode for editing my =.mbsyncrc= file. I + might release it as a package, but for now I keep it with the rest + of my configuration. + + #+BEGIN_SRC emacs-lisp + (ensure-library mbsync-conf-mode + :path "vendor-lisp/mbsync-conf-mode") + #+END_SRC + + Since it isn't installed by package.el, I need to specify the + autoload myself. + + #+BEGIN_SRC emacs-lisp + (autoload 'mbsync-conf-mode "mbsync-conf-mode" + "Major mode for editing mbsync configuration files." + :interactive) + #+END_SRC + + I also need to add it to the =auto-mode-alist= so ~.mbsyncrc~ is + opened with mbsync conf mode. + + #+BEGIN_SRC emacs-lisp + (add-to-list 'auto-mode-alist '("\\.mbsyncrc\\'" . mbsync-conf-mode)) + #+END_SRC + +** Msmtprc mode + + I wrote a simple major-mode for editing my =.msmtprc= file. I might + release it as a package, but for now I keep it with the rest of my + configuration. + + #+BEGIN_SRC emacs-lisp + (ensure-library msmtprc-mode + :path "vendor-lisp/msmtprc-mode") + #+END_SRC + + Since it isn't installed by package.el, I need to specify the + autoload myself. + + #+BEGIN_SRC emacs-lisp + (autoload 'msmtprc-mode "msmtprc-mode" + "Major mode for editing msmtp configuration files." + :interactive) + #+END_SRC + + I also need to add it to the =auto-mode-alist= so ~.msmtprc~ is + opened with msmtprc mode. + + #+BEGIN_SRC emacs-lisp + (add-to-list 'auto-mode-alist '("\\.msmtprc\\'" . msmtprc-mode)) + #+END_SRC + +** Git commit mode + + Enable =electric-quote-local-mode= to easily type nice-looking + quotes while writing commits. + + #+BEGIN_SRC emacs-lisp + (add-hook 'git-commit-mode-hook 'electric-quote-local-mode) + #+END_SRC + +** Python mode + + Enable electric pair mode. + + #+BEGIN_SRC emacs-lisp + (add-hook 'python-mode-hook 'electric-pair-local-mode) + #+END_SRC + +* Applications + +** Magit + + Magit is a very nice interface to Git for Emacs. It allows you to + do just about anything with Git without leaving the comfort of your + Emacs session. + + #+BEGIN_SRC emacs-lisp + (ensure-library magit) + #+END_SRC + +** Gnus + + Gnus is one of the most extensible Email programs on the + planet. And it's not even made for email but NNTP. + + Store all Gnus-related data in my data directory. + + #+BEGIN_SRC emacs-lisp + (eval-when-compile (require 'gnus)) + + (with-eval-after-load 'gnus + (setq gnus-directory (oni:data-location "News") + gnus-article-save-directory gnus-directory + gnus-cache-directory gnus-directory + gnus-kill-files-directory gnus-directory)) + #+END_SRC + + Store all Mail source-related data in my data directory. + + #+BEGIN_SRC emacs-lisp + (eval-when-compile (require 'mail-source)) + + (with-eval-after-load 'mail-source + (setq mail-source-directory (oni:data-location "Mail"))) + #+END_SRC + + Store all message-related data in the same place as the Mail source + data. + + #+BEGIN_SRC emacs-lisp + (eval-when-compile (require 'message)) + + (with-eval-after-load 'message + (setq message-directory mail-source-directory)) + #+END_SRC + + Store all nnfolder-related data in the same place as the Mail + source data. + + #+BEGIN_SRC emacs-lisp + (eval-when-compile (require 'nnfolder)) + + (with-eval-after-load 'nnfolder + (setq nnfolder-directory mail-source-directory)) + #+END_SRC + + Use msmtp to send mail. + + #+BEGIN_SRC emacs-lisp + (eval-when-compile (require 'sendmail)) + + (with-eval-after-load 'sendmail + (setq send-mail-function 'sendmail-send-it) + (setq sendmail-program "/usr/bin/msmtp")) + #+END_SRC + +*** ryuslash.org + + Set my main email address as the primary select method for Gnus. + + #+BEGIN_SRC emacs-lisp + (with-eval-after-load 'gnus + (setq gnus-select-method + '(nnmaildir "ryuslash" (directory "~/documents/mail/ryuslash/")))) + #+END_SRC + + When sending mail from the ryuslash inbox, use the ryuslash msmtp + account. + + #+BEGIN_SRC emacs-lisp + (eval-when-compile (require 'gnus-msg)) + + (with-eval-after-load 'gnus + (add-to-list 'gnus-posting-styles + '(".*" + (address "tom@ryuslash.org") + (eval (setq message-sendmail-extra-arguments + '("-a" "ryuslash")))))) + #+END_SRC + +*** picturefix + + Add my work email account as a secondary select method. + + #+BEGIN_SRC emacs-lisp + (add-to-list 'gnus-secondary-select-methods + '(nnmaildir "picturefix" + (directory "~/documents/mail/picturefix/"))) + #+END_SRC + + When sending mail from the picturefix account, use the picturefix + msmtp account and set the proper name and email address. + + #+BEGIN_SRC emacs-lisp + (with-eval-after-load 'gnus + (add-to-list 'gnus-posting-styles + '("picturefix:" + (name "Tom Willemsen") + (address "tom@picturefix.nl") + (eval (setq message-sendmail-extra-arguments + '("-a" "picturefix")))))) + #+END_SRC + +* Custom + + Put the customize settings in a different file so that Emacs doesn't + have to modify this file whenever something changes through + customize. I put this into my init file last so any settings made in + there *can* overwrite the ones in the rest of the file, not that I + usually like to do that. + + #+BEGIN_SRC emacs-lisp + (setq custom-file (concat user-emacs-directory "custom.el")) + (load custom-file) + #+END_SRC -- cgit v1.2.3-54-g00ecf