#+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 Add the directory with my mode-specific configuration files to the load path. #+BEGIN_SRC emacs-lisp (add-to-list 'load-path (locate-user-emacs-file "init/")) #+END_SRC Add all my vendored packages to the load path. #+BEGIN_SRC emacs-lisp (eval-and-compile (mapc (lambda (d) (add-to-list 'load-path d)) (directory-files (locate-user-emacs-file "vendor-lisp/") t "^[^.]"))) #+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 Some actions produce a lot of output that is usually uninteresting during compilation. However, this information may be crucial when an error occurs. So for these actions I can use this macro, which stores all sent messages in a temporary buffer and prints them when an error occurs, and hides them when it doesn't. #+BEGIN_SRC emacs-lisp (defmacro silently (title &rest body) "Only output something when an error occurs. Prefix with TITLE any output that occurs while executing BODY, but only when an error occurs, otherwise discard it." (declare (indent 1)) (let ((buffer-var (cl-gensym)) (error-var (cl-gensym))) `(with-temp-buffer (let ((,buffer-var (current-buffer))) (cl-letf (((symbol-function 'message) (lambda (msg &rest args) (with-current-buffer ,buffer-var (insert " " (apply 'format msg args) "\n"))))) (condition-case ,error-var (progn ,@body) (error (princ ,(concat title " output:\n")) (princ (with-current-buffer ,buffer-var (buffer-string))) (princ "Error:\n") (princ " ") (princ (cadr ,error-var)) (princ "\n")))))))) #+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 (let* ((not-installed (seq-remove 'package-installed-p package-selected-packages)) (available (seq-filter (lambda (p) (assq p package-archive-contents)) not-installed)) (difference (- (length not-installed) (length available)))) (when (> difference 0) (silently "Refresh packages" (package-refresh-contents))) (when available (mapc (lambda (p) (package-install p t)) available)))) #+END_SRC * Site lisp Setup everything so that any autoloads in ~site-lisp/~ get loaded and can be used. #+BEGIN_SRC emacs-lisp (eval-and-compile (add-to-list 'load-path (locate-user-emacs-file "site-lisp/")) (let ((loaddefs (locate-user-emacs-file "site-lisp/site-autoloads.el"))) (when (file-exists-p loaddefs) (load loaddefs)))) #+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-15")) #+END_SRC * Internal border For aesthetics I like to have a thick border on the inside of my Emacs window. I have the same border in URxvt, but I haven't found out how to add it to Conkeror yet. #+BEGIN_SRC emacs-lisp (add-to-list 'default-frame-alist '(internal-border-width . 15)) #+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 * Cursor Use a bar cursor instead of a box. #+BEGIN_SRC emacs-lisp (setq-default cursor-type '(bar . 2)) #+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 (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 * Long lines By default Emacs wraps long lines around to the next line when they reach the far end of the window. However I prefer to have them truncated instead. #+BEGIN_SRC emacs-lisp (setq-default truncate-lines t) #+END_SRC * Theme #+BEGIN_SRC emacs-lisp (add-to-list 'custom-theme-load-path (concat user-emacs-directory "vendor-lisp/yoshi-theme")) (load-theme 'yoshi :no-confirm) #+END_SRC * Diminish I really don't need to see some of the minor modes. #+BEGIN_SRC emacs-lisp (require 'diminish) #+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. 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 Don't show that ivy is enabled in the mode-line. It's enabled globally and I'll notice it from other things anyway (like it showing up). #+BEGIN_SRC emacs-lisp (diminish 'ivy-mode) #+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. 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 Hide dotfiles in =counsel-find-file=. #+BEGIN_SRC emacs-lisp (setq counsel-find-file-ignore-regexp (rx (or (and bos ".") (and ".zwc" eos)))) #+END_SRC Enable Counsel. #+BEGIN_SRC emacs-lisp (counsel-mode) #+END_SRC Don't show that counsel is enabled in the mode-line. It's enabled globally and I'll notice whenever I press M-x for example. #+BEGIN_SRC emacs-lisp (diminish '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 * Automatic alignment Emacs has some powerful automatic alignment features. #+BEGIN_SRC emacs-lisp (eval-when-compile (require 'align)) #+END_SRC ** CSS Align CSS files like so: #+BEGIN_SRC css body { color: #ffffff; } .some-class { background-color: #ffffff; } #some-id { width: 200px; } .some-more-class { color: #ffffff; background-color: #ffffff; width: 200px; } #+END_SRC #+BEGIN_SRC emacs-lisp (with-eval-after-load 'align ;; Keep these in order. They are each added to the _front_ of the ;; list and are applied in order. Changing their order will change ;; the results. (add-to-list 'align-rules-list `(css-closing-brace (regexp . ,(rx (group (0+ whitespace)) "}" eol)) (group . (1)) (modes . '(scss-mode css-mode)))) (add-to-list 'align-rules-list `(css-colons (regexp . ,(rx bol (0+ whitespace) (1+ (any (?a . ?z) ?- ?$)) ":" (group (0+ whitespace)) (0+ nonl) ";" eol)) (group . (1)) (modes . '(scss-mode css-mode)) (repeat . t))) (add-to-list 'align-rules-list `(css-opening-brace (regexp . ,(rx bol (0+ whitespace) (0+ (any ?# ?. ?, ?\s ?& ?: ?- (?a . ?z) (?A . ?Z) (?0 . ?9))) (any (?a . ?z) (?A . ?Z) (?0 . ?9)) (group (0+ whitespace)) "{" (0+ nonl))) (group . (1)) (modes . '(scss-mode css-mode))))) #+END_SRC ** PHP In PHP code it's nice to have any ~=>~ aligned. #+BEGIN_SRC php 'bar', 'frob' => 'baz' ); ?> #+END_SRC #+BEGIN_SRC emacs-lisp (with-eval-after-load 'align (add-to-list 'align-rules-list `(php-array-arrow (regexp . ,(rx any (group whitespace) "=>" any)) (group . (1)) (modes . '(php-mode web-mode)) (repeat . t)))) #+END_SRC * Url browsing Use Conkeror to open URLs. #+BEGIN_SRC emacs-lisp (eval-when-compile (require 'browse-url)) (with-eval-after-load 'browse-url (setq browse-url-browser-function 'browse-url-conkeror)) #+END_SRC * Minibuffer Enable paredit mode in the minibuffer. #+BEGIN_SRC emacs-lisp (add-hook 'minibuffer-setup-hook 'electric-pair-local-mode) #+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. Don't show that paredit is enabled, it should be obvious from the effects it has. This will save some precious real-estate on my mode line. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'paredit (diminish 'paredit-mode)) #+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 ** Flycheck Flycheck lets me see (compiler) errors, warnings and info messages while writing code. When developing packages with Cask, some special care needs to be taken to ensure the checkers work correctly. #+BEGIN_SRC emacs-lisp (add-hook 'flycheck-mode-hook 'flycheck-cask-setup) #+END_SRC I disable the pylint and pyflakes checkers because they don't seem to add much except noise when used together with flake8. Also pylint seems hell-bent on making Python written like a statically-typed langauge. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'flycheck (mapc (lambda (c) (delq c flycheck-checkers)) '(python-pylint python-pyflakes))) #+END_SRC Also show which columns messages appear in. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'flycheck (setq flycheck-highlighting-mode 'columns)) #+END_SRC Show the error message at point in a tooltip. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'flycheck (require 'flycheck-pos-tip) (flycheck-pos-tip-mode)) #+END_SRC Shorten the flycheck mode line lighter. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'flycheck (setq flycheck-mode-line-prefix "✓")) #+END_SRC ** Auto revert mode ARev isn't very descriptive, and fairly wide. Use a font-awesome icon instead. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'autorevert (diminish 'auto-revert-mode (propertize (concat " " (char-to-string #xf021)) 'face '(:family "Font Awesome" :height 0.75)))) #+END_SRC ** Auto fill mode "Fill" is fine as a mode-line lighter, but I prefer something shorter. #+BEGIN_SRC emacs-lisp (diminish 'auto-fill-function (propertize (concat " " (char-to-string #xf149)) 'face '(:family "Font Awesome" :height 0.75))) #+END_SRC ** Diff highlight mode Show the state of lines added, changed and removed since the last commit. #+BEGIN_SRC emacs-lisp (require 'diff-hl) (global-diff-hl-mode) #+END_SRC ** Hydra Hydra is an interesting way of managing keybindings, I want to experiment. Add a hydra for org. #+BEGIN_SRC emacs-lisp (global-set-key (kbd "C-c o") 'oni-hydra-org/body) #+END_SRC Add a hydra for magit. #+BEGIN_SRC emacs-lisp (global-set-key (kbd "C-c m") 'oni-hydra-magit/body) #+END_SRC ** Isearch Replace the Isearch mode line lighter with a magnifying glass icon. #+BEGIN_SRC emacs-lisp (diminish 'isearch-mode (propertize (concat " " (char-to-string #xf002)) 'face '(:family "Font Awesome" :height 0.75))) #+END_SRC ** Projectile Projectile is, thus far, the best project module for Emacs. Set the known projects file before loading projectile because projectile loads the known projects as it's loading, not after. #+BEGIN_SRC emacs-lisp (setq projectile-known-projects-file (oni:data-location "projectile-bookmarks.eld")) #+END_SRC Since I'm just going to use it anyway, require it immediately. #+BEGIN_SRC emacs-lisp (require 'projectile) #+END_SRC I don't like that projectile tries to take up so much space in my mode-line, so I try to make it a little shorter. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'projectile (setq projectile-mode-line '(:eval (if (file-remote-p default-directory) " P" (let ((name (projectile-project-name))) (if (string= "-" name) "" (format " P[%s]" name))))))) #+END_SRC Store projectile files in my data dir. #+BEGIN_SRC emacs-lisp (setq projectile-cache-file (oni:data-location "projectile.cache")) #+END_SRC Enable it globally so I can always switch to/from projects. #+BEGIN_SRC emacs-lisp (projectile-mode) #+END_SRC Use Ivy for projectile completions. #+BEGIN_SRC emacs-lisp (setq projectile-completion-system 'ivy) #+END_SRC ** Server mode Diminish server mode with a nice icon. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'server (diminish 'server-buffer-clients (propertize (concat " " (char-to-string #xf233)) 'face '(:family "Font Awesome" :height 0.75)))) #+END_SRC * Major modes Configuration for major modes is specified in dedicated configuration files. - [[file:init/js-mode.org][js-mode]] :: JavaScript mode is used by me for json files. js2-mode doesn't work very nicely with json, always showing syntax errors. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'js (load "oni-js-mode-init")) #+END_SRC - [[file:init/php-mode-init.org][php-mode]] :: I use PHP mode for files that only contain PHP code, no HTML or anything. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'php-mode (load "oni-php-mode-init")) #+END_SRC - [[file:init/sh-mode-init.org][sh-mode]] :: Used for most types of shell scripting (bash, zsh, etc.). #+BEGIN_SRC emacs-lisp (with-eval-after-load 'sh-mode (load "oni-sh-mode-init")) #+END_SRC ** 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 'ielm-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. 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. 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 Enable syntax and style checking with flycheck. #+BEGIN_SRC emacs-lisp (add-hook 'python-mode-hook 'flycheck-mode) #+END_SRC ** Web mode Web mode is a good general-purpose web template mode. It works well with many template languages and PHP as well. Enable a specialized whitespace mode for web mode that shows tabs at the beginning of a line. #+BEGIN_SRC emacs-lisp (add-hook 'web-mode-hook 'oni-whitespace-only-tabs-mode) #+END_SRC ** Makefile mode Show tabs in Makefiles. Tabs are required at the beginning of any non-continuation line in a recipe. I don't use it for indenting, however. #+BEGIN_SRC emacs-lisp (add-hook 'makefile-mode-hook 'oni-whitespace-only-tabs-mode) #+END_SRC Enable electric pairing. #+BEGIN_SRC emacs-lisp (add-hook 'makefile-mode-hook 'electric-pair-local-mode) #+END_SRC ** CSS mode Enable electric indent mode. #+BEGIN_SRC emacs-lisp (add-hook 'css-mode-hook 'electric-indent-local-mode) #+END_SRC ** Clojure mode Install extra font-locking for clojure. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'clojure-mode (require 'clojure-mode-extra-font-locking)) #+END_SRC Enable paredit mode. #+BEGIN_SRC emacs-lisp (add-hook 'clojure-mode-hook 'paredit-mode) #+END_SRC Use the clojure repl as the inferior lisp mode. #+BEGIN_SRC emacs-lisp (eval-when-compile (require 'inf-lisp)) (defun oni:clojure-set-inferior-lisp () (setq inferior-lisp-program "lein repl")) #+END_SRC Add a little more font locking still, and some indentation. This is included in the Clojure for the Brave and True configuration. #+BEGIN_SRC emacs-lisp (add-hook 'clojure-mode-hook 'oni-clojure-add-font-lock) (add-hook 'clojure-mode-hook 'oni-clojure-add-indent) #+END_SRC ** Cider mode Cider is like Slime for Common Lisp. This configuration is copied from the one provided by Clojure for the Brave and True. Provides minibuffer documentation for the code you're typing into the repl. #+BEGIN_SRC emacs-lisp (add-hook 'cider-mode-hook 'cider-turn-on-eldoc-mode) #+END_SRC Go right to the REPL buffer when it's finished connecting #+BEGIN_SRC emacs-lisp (with-eval-after-load 'cider (setq cider-repl-pop-to-buffer-on-connect t)) #+END_SRC When there's a cider error, show its buffer and switch to it. #+BEGIN_SRC emacs-lisp (setq cider-show-error-buffer t cider-auto-select-error-buffer t) #+END_SRC Where to store the cider history. #+BEGIN_SRC emacs-lisp (setq cider-repl-history-file (oni:data-location "cider-history")) #+END_SRC Wrap when navigating history. #+BEGIN_SRC emacs-lisp (setq cider-repl-wrap-history t) #+END_SRC Enable paredit in your REPL. #+BEGIN_SRC emacs-lisp (add-hook 'cider-repl-mode-hook 'paredit-mode) #+END_SRC * Applications - [[file:init/dired-init.org][Dired]] :: The Emacs file manager. Very powerful, and I don't use it enough /yet/. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'dired (load "oni-dired-init")) #+END_SRC - [[file:init/magit-init.org][Magit]] :: The Emacs git interface. By now I think I may know magit better than the git cli. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'magit (load "oni-magit-init")) #+END_SRC - [[file:init/ediff-init.org][Ediff]] :: A reall diff application. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'ediff (load "oni-ediff-init")) #+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 (oni:data-location "Mail"))) #+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 (oni:data-location "Mail"))) #+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 Tell Gnus I'm not a novice anymore. One of the features of Gnus I use a lot is deleting messages and as long as Gnus thinks I'm a novice it will ask me if I'm sure every single time. #+BEGIN_SRC emacs-lisp (setq gnus-novice-user nil) #+END_SRC Add a keybinding to the Gnus summary mode to easily delete messages. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'gnus (define-key gnus-summary-mode-map (kbd "M-d") 'oni-gnus-delete-forward)) #+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-msg (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 (with-eval-after-load 'gnus (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-msg (add-to-list 'gnus-posting-styles '("picturefix:" (name "Tom Willemsen") (address "tom@picturefix.nl") (eval (setq message-sendmail-extra-arguments '("-a" "picturefix")))))) #+END_SRC *** gmail Add my other personal email as a secondary select method. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'gnus (add-to-list 'gnus-secondary-select-methods '(nnmaildir "gmail" (directory "~/documents/mail/gmail/")))) #+END_SRC When sending mail from the gmail account, use the gmail msmtp accound and set the proper email address. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'gnus-msg (add-to-list 'gnus-posting-styles '("gmail:" (name "Tom Willemse") (address "ryuslash@gmail.com") (eval (setq message-sendmail-extra-arguments '("-a" "gmail")))))) #+END_SRC ** Linewise user-interface This is the library used by Circe and Slack to display messages. #+BEGIN_SRC emacs-lisp (eval-when-compile (require 'lui)) #+END_SRC Put the time stamp in lui buffers in the right margin. This gives the text some extra room. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'lui (setq lui-time-stamp-position 'right-margin)) #+END_SRC Remove the "[]" from the time stamp, it's not really necessary. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'lui (setq lui-time-stamp-format "%H:%M")) #+END_SRC Give the right margin just enough room to show the time-stamps, no more, no less. #+BEGIN_SRC emacs-lisp (defun oni:set-circe-margin-width () (setq right-margin-width 5)) (add-hook 'lui-mode-hook #'oni:set-circe-margin-width) #+END_SRC Fix the wrap prefix so that text at the prompt is aligned properly. #+BEGIN_SRC emacs-lisp (defun oni:set-lui-prompt-wrap-prefix () (setq wrap-prefix " ")) (add-hook 'lui-mode-hook #'oni:set-lui-prompt-wrap-prefix) #+END_SRC Enable visual line mode in lui buffers so my text doesn't go off-screen. #+BEGIN_SRC emacs-lisp (add-hook 'lui-mode-hook 'visual-line-mode) #+END_SRC Turn off filling in lui buffers. I use visual-line mode instead. #+BEGIN_SRC emacs-lisp (setq lui-fill-type nil) #+END_SRC ** Circe I switched to Circe from ERC because I couldn't make the customizations I wanted to, Circe seems much better at this. Make sure that Emacs knows these function exist when the file is being compiled. #+BEGIN_SRC emacs-lisp (eval-when-compile (require 'oni-circe)) #+END_SRC I spend most of my time on IRC on Freenode. #+BEGIN_SRC emacs-lisp (eval-when-compile (require 'circe)) (with-eval-after-load 'circe (add-to-list 'circe-network-options `("Freenode" :nick "ryuslash" :channels ("#emacs" "#mowedline" "#ninthfloor" "#dispass" "#linuxvoice" "#conkeror") :nickserv-password ,(oni-circe-get-password-for "irc.freenode.net")))) #+END_SRC Sometimes I watch some Twitch streams as well. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'circe (add-to-list 'circe-network-options `("Twitch" :use-tls nil :nick "ryuslash" :host "irc.twitch.tv" :pass ,(oni-circe-get-password-for "irc.twitch.tv") :port 6667))) #+END_SRC Enable coloring of nicks. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'circe (require 'circe-color-nicks) (enable-circe-color-nicks)) #+END_SRC Align all nicks. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'circe (require 'sermon) (enable-sermon)) #+END_SRC ** Org Tell org-mode to fontify code blocks in their specified languages. #+BEGIN_SRC emacs-lisp (eval-when-compile (require 'org)) (with-eval-after-load 'org (setq org-src-fontify-natively t)) #+END_SRC Enable automatic text filling for org-mode. #+BEGIN_SRC emacs-lisp (add-hook 'org-mode-hook 'auto-fill-mode) #+END_SRC ** Jabber I like using XMPP to talk to people, jabber.el is very good at this. #+BEGIN_SRC emacs-lisp (eval-when-compile (require 'jabber)) #+END_SRC Add my account. #+BEGIN_SRC emacs-lisp (setq jabber-account-list `((,(concat "ryuslash@dukgo.com/" (system-name))) (:connection-type . starttls))) #+END_SRC Store any persistent data in the data directory. #+BEGIN_SRC emacs-lisp (setq jabber-avatar-cache-directory (oni:data-location "jabber/avatars/") jabber-history-dir (oni:data-location "jabber/hist/")) #+END_SRC Change the default prompts. #+BEGIN_SRC emacs-lisp (setq jabber-chat-buffer-format "+%n" jabber-chat-foreign-prompt-format "%t %u " jabber-chat-local-prompt-format "%t %u " jabber-chat-delayed-time-format "%H:%M" jabber-groupchat-buffer-format "++%n" jabber-groupchat-prompt-format "%t %u ") #+END_SRC Don't show avatars, publish or retrieve avatars. #+BEGIN_SRC emacs-lisp (setq jabber-chat-buffer-show-avatar nil jabber-vcard-avatars-publish nil jabber-vcard-avatars-retrieve nil) #+END_SRC Don't fill long lines in jabber chat buffers, but use visual line mode. #+BEGIN_SRC emacs-lisp (setq jabber-chat-fill-long-lines nil) (add-hook 'jabber-chat-mode-hook 'visual-line-mode) #+END_SRC Don't send notifications about chat states. #+BEGIN_SRC emacs-lisp (setq jabber-chatstates-confirm nil) #+END_SRC Colorize text in multi-user chats. #+BEGIN_SRC emacs-lisp (setq jabber-muc-colorize-local t jabber-muc-colorize-foreign t) #+END_SRC Enable recording history. #+BEGIN_SRC emacs-lisp (setq jabber-history-enabled t jabber-use-global-history nil) #+END_SRC Clean up the default view of the roster buffer. #+BEGIN_SRC emacs-lisp (setq jabber-roster-show-bindings nil jabber-show-offline-contacts nil) (add-hook 'jabber-roster-mode-hook 'oni-jabber-set-roster-mode-line) #+END_SRC Use libnotify to send jabber notifications. #+BEGIN_SRC emacs-lisp (add-hook 'jabber-alert-message-hooks 'jabber-message-libnotify) (add-hook 'jabber-alert-muc-hooks 'jabber-muc-libnotify) #+END_SRC Don't echo presence changes in the mode line, show them in the relevant buffer instead. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'jabber-alert (remove-hook 'jabber-alert-presence-hooks 'jabber-presence-echo)) (add-hook 'jabber-alert-presence-hooks 'oni-jabber-show-status-in-buffer) #+END_SRC Set the default directory to my home directory for jabber chat buffers. #+BEGIN_SRC emacs-lisp (defun oni:set-default-directory () (setq default-directory "~/")) (add-hook 'jabber-chat-mode-hook 'oni:set-default-directory) #+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