#+TITLE: Tom-Emacs Interface #+STARTUP: content #+MACRO: key @@html:$1@@@@ascii:`$1'@@ 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". * Preamble These are some settings that need to be taken care of before the rest. ** Lexical binding To start off, first I need to enable lexical binding. It offers better performance in some circumstances and enables me to use cool things such as closures. #+BEGIN_SRC emacs-lisp :padline no ;; -*- lexical-binding: t; -*- #+END_SRC ** Load path Emacs' load path is where it looks to find Emacs Lisp files when confronted with a ~load~ or ~require~ form. Most of my packages are managed through the package manager, but not all of them. *** Mode-specific configuration directory 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 *** Vendor directory 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 *** 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 Some things are best abstracted into special functions and/or macros so as not to make the setting itself too verbose. I have some helper functions stored away in a separate file. #+BEGIN_SRC emacs-lisp (require 'oni-helpers) #+END_SRC ** Package configuration Since Emacs 24 there has been a package manager in Emacs. A lot of packages have been added to a number of package repositories. *** Load the package manager 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 package archives The default package archive has some pretty neat packages, but the Melpa package archive is much more popular because it doesn't require copyright assignment to upload packages to it and it is well integrated with git. I add these archives both at compile-time and run-time because I install missing packages at compile-time. If the archives aren't added then, the packages can't be installed. **** Add Melpa Add the Melpa package archive because I like living on the bleeding edge. #+BEGIN_SRC emacs-lisp (eval-and-compile (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))) #+END_SRC **** Add org Add the org package archive because it hosts the latest org development release, and as stated above, I like living on the bleeding edge. #+BEGIN_SRC emacs-lisp (eval-and-compile (add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/"))) #+END_SRC *** Initialize the package manager 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 *** Install missing packages 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. Afterwards #+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 * General settings These settings are generally not associated with a specific mode, but affect how the core of Emacs behaves. ** Files There are a lot of files that Emacs uses to keep track of things. I usually prefer to keep them all in one place together, instead of spreading them around the filesystem. With exceptions of course. *** 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. **** Auto save files 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 **** Auto save indexes Place the files which contain the indexes of 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 *** Additional file type mappings Load =*.js= files with [[JavaScript IDE mode]]. ~js2-mode~ is a better JavaScript mode than plain old ~js-mode~. #+BEGIN_SRC emacs-lisp (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode)) #+END_SRC ** Global Keybindings Bind expand-region, which functions a lot like a better ~mark-sexp~. #+BEGIN_SRC emacs-lisp (global-set-key (kbd "C-M-SPC") 'er/expand-region) #+END_SRC Using multiple cursors can be really handy when you have the same edits to make on multiple levels. #+BEGIN_SRC emacs-lisp (global-set-key (kbd "M-+") 'mc/mark-next-like-this) #+END_SRC I've been looking for something like Embrace for a long time. I really like the =surround.vim= module for vim (which I've only used as =evil-surround= in =evil-mode=). Though because Emacs is not a moded editor like vim, it's hard to find the right way to do things. #+BEGIN_SRC emacs-lisp (global-set-key (kbd "C-c (") 'embrace-commander) #+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 * Typographic style Emacs being a text editor has options on how to handle your text. ** Whitespace Even though whitespace technically isn't seen, it can still be an eyesore and highly annoying, you must always keep it well in check. *** Remove trailing whitespace before saving 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 *** Make sure there is a newline at the end of the file 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 *** Tabs Unless absolutely necessary, I really don't want any tabs in my code. **** Don't use tabs for indentation Generally I prefer using spaces over tabs. Especially for lisp-like languages. #+BEGIN_SRC emacs-lisp (setq-default indent-tabs-mode nil) #+END_SRC **** Display tabs as 4 columns wide 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 *** Sentences end with a single space I'm not an American, and I don't follow American grammatical rules when I write. I have always ended my sentences with a single space and I'm sure I'll always keep doing that. #+BEGIN_SRC emacs-lisp (setq sentence-end-double-space nil) #+END_SRC ** User Interface Emacs' user interface is very configurable, from themes to hiding unnecessary elements. *** Inhibit startup screen I've been using Emacs long enough not to need the startup screen anymore. I don't see it on my PC where I start Emacs in daemon mode, but on my laptop I always start it normally, so it gets in the way. #+BEGIN_SRC emacs-lisp (setq inhibit-startup-screen t) #+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 *** 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 *** Suspend The {{{key(C-z)}}} key in a terminal suspends the current application to the background and lets you do other things on the command line without having to fully close the application. In GUI Emacs this minimizes the current frame. I have no place for it to minimize to (no task bar or anything), so this just freezes my frame. To prevent this from happening I unbind the {{{key(C-z)}}} key. #+BEGIN_SRC emacs-lisp (global-unset-key (kbd "C-z")) #+END_SRC *** Don't ask for yes or no One of the more annoying things can be when Emacs starts asking for confirmation and you have to type in =yes= or =no=. I get that this is to prevent you from accidentally performing an action, but just =y= or =n= has since 2008 not made me accidentally perform any action I didn't mean to. #+BEGIN_SRC emacs-lisp (defalias 'yes-or-no-p 'y-or-n-p) #+END_SRC *** Show any matching parenthesis When working in Lisp code (but other code as well) it can be very handy to see which parenthesis the one near the cursor matches. #+BEGIN_SRC emacs-lisp (show-paren-mode) #+END_SRC * Theme Load my personal theme. I sometimes change it to a different theme, but for some reason I always come crawling back to it. #+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 Load my personal SVG mode-line theme. #+BEGIN_SRC emacs-lisp (require 'svg-mode-line-themes) (require 'oni-smt) (smt/enable) (smt/set-theme 'oni-smt) #+END_SRC Because SVG mode-line themes doesn't include the box around the mode-line, remove it (my personal theme adds it as padding). #+BEGIN_SRC emacs-lisp (set-face-attribute 'mode-line nil :box nil) (set-face-attribute 'mode-line-inactive nil :box nil) #+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 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 {{{key(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 {{{key(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 Firefox 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-firefox)) #+END_SRC * Minibuffer Enable Electric pair mode in the minibuffer. I tried Paredit for a little while, but I forgot that it isn't always only lisp that I'm entering in the minibuffer. #+BEGIN_SRC emacs-lisp (add-hook 'minibuffer-setup-hook 'electric-pair-local-mode) #+END_SRC * Shackle Shackle is an abstraction over ~display-buffer-alist~. #+BEGIN_SRC emacs-lisp (require 'shackle) (shackle-mode) #+END_SRC * Libraries - [[file:init/oni-shr-init.org][shr]] #+BEGIN_SRC emacs-lisp (with-eval-after-load 'shr (load "oni-shr-init")) #+END_SRC * Minor modes - [[file:init/oni-company-init.org][Company mode]] :: A better auto completion system than auto complete. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'company (load "oni-company-init")) #+END_SRC ** 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 {{{key(C-j)}}} and {{{key(RET)}}} keys. I prefer the original situation because my muscle-memory still remembers to use {{{key(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 Add p4 options for diff-hl to fix diff highlighting in Perforce projects. #+BEGIN_SRC emacs-lisp (defun oni:with-diff-hl-p4-args (orig-fun &rest args) (let ((p4-lowlevel-diff-switches '("-du0"))) (apply orig-fun args))) (with-eval-after-load 'vc-p4 (add-function :around (symbol-function 'diff-hl-changes-buffer) #'oni:with-diff-hl-p4-args)) #+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 Add ~yarn.lock~ as a possible root file for Projectile. #+BEGIN_SRC emacs-lisp (add-to-list 'projectile-project-root-files "yarn.lock") #+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 ** Slime Slime is crucial for developing Common Lisp programs. Set the available Lisp implementations and the default implementation to use. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'slime (setq slime-lisp-implementations '((sbcl ("sbcl" "--noinform") :coding-system utf-8-unix) (clisp ("clisp") :coding-system utf-8-unix))) (setq slime-default-lisp 'sbcl) (slime-setup '(slime-fancy slime-company))) #+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 - [[file:init/oni-css-mode-init.org][css-mode]] :: CSS and SCSS mode are used for stylesheets! #+BEGIN_SRC emacs-lisp (with-eval-after-load 'css-mode (load "oni-css-mode-init")) #+END_SRC - [[file:init/oni-emacs-lisp-mode-init.org][emacs-lisp-mode]] :: Emacs lisp is what powers all this Emacs awesomeness. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'elisp-mode (load "oni-emacs-lisp-mode-init")) #+END_SRC - [[file:init/oni-scheme-init.org][scheme-mode]] :: Scheme is an awesome lisp variant. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'scheme (load "oni-scheme-init")) #+END_SRC - [[file:init/oni-compilation-init.org][compilation-mode]] :: Major mode for various compilation processes. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'compile (load "oni-compilation-init")) #+END_SRC - [[file:init/oni-java-init.org][java-mode]] :: Major mode for the Java programming language. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'cc-mode (load "oni-java-init")) #+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 ** 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 Enable rainbow delimiters. #+BEGIN_SRC emacs-lisp (add-hook 'clojure-mode-hook 'rainbow-delimiters-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. 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 ** C Mode Enable electric pair mode. #+BEGIN_SRC emacs-lisp (add-hook 'c-mode-hook 'electric-pair-local-mode) #+END_SRC Enable electric indent mode. #+BEGIN_SRC emacs-lisp (add-hook 'c-mode-hook 'electric-indent-local-mode) #+END_SRC ** Lisp mode Enable paredit mode for Common Lisp programming. #+BEGIN_SRC emacs-lisp (add-hook 'lisp-mode-hook 'paredit-mode) #+END_SRC Enable rainbow-delimiters mode for Common Lisp programming. #+BEGIN_SRC emacs-lisp (add-hook 'lisp-mode-hook 'rainbow-delimiters-mode) #+END_SRC Enable company mode for Common Lisp programmind. #+BEGIN_SRC emacs-lisp (add-hook 'lisp-mode-hook 'company-mode) #+END_SRC ** JavaScript IDE mode :PROPERTIES: :header-args: :tangle "init/oni-js2-init.el" :END: Since ~js2-mode~ isn't loaded when Emacs starts put the configuration in a different file so that it doesn't cause a slowdown in startup time. #+BEGIN_SRC emacs-lisp :tangle yes (with-eval-after-load 'js2-mode (load "oni-js2-init")) #+END_SRC Keep the byte-compiler happy by requiring ~js2-mode~, by this time it will have been loaded anyway. #+BEGIN_SRC emacs-lisp (require 'js2-mode) #+END_SRC Silence warnings about trailing commas in JavaScript code. I usually write code that goes through Babel or something similar and doesn't actually die when a trailing comma is present. Also this should really be handled by a linter such as eslint. #+BEGIN_SRC emacs-lisp (setq js2-strict-trailing-comma-warning nil) #+END_SRC Enable ~subword-mode~ because a lot of JavaScript identifiers look either like =someIdentifier= or =SomeClassName=. #+BEGIN_SRC emacs-lisp (add-hook 'js2-mode-hook 'subword-mode) #+END_SRC Enable ~flycheck-mode~ to run syntax checkers such as eslint. #+BEGIN_SRC emacs-lisp (add-hook 'js2-mode-hook 'flycheck-mode) #+END_SRC Set the default indentation to 2 spaces. #+BEGIN_SRC emacs-lisp (setq js2-basic-offset 2) #+END_SRC Enable company mode for completions. #+BEGIN_SRC emacs-lisp (add-hook 'js2-mode-hook 'company-mode) #+END_SRC ** HTML mode Enable electric pairing so I don't have to worry about closing =<= and ="= and such. #+BEGIN_SRC emacs-lisp (add-hook 'html-mode-hook 'electric-pair-local-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/oni-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 - [[file:init/oni-eshell-init.org][Eshell]] :: The best shell on the planet. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'eshell (load "oni-eshell-init")) #+END_SRC - [[file:init/oni-slack-init.org][Slack]] :: A slack client for Emacs. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'slack (load "oni-slack-init")) #+END_SRC - [[file:init/oni-circe-init.org][Circe]] :: A very nice and clean IRC client for Emacs. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'circe (load "oni-circe-init")) #+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 ** 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 %n " jabber-chat-local-prompt-format "%t %n " jabber-chat-delayed-time-format "%H:%M" jabber-groupchat-buffer-format "++%n" jabber-groupchat-prompt-format "%t %n ") #+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 ** Gnus :PROPERTIES: :header-args: :tangle "init/oni-gnus-init.el" :END: Gnus is the very extensible Emacs news reader, which just happens to also function very well as a mail reader. Since it is so extensible and also configurable the configuration for it tends to get big, so I split it into a separate file. #+BEGIN_SRC emacs-lisp :tangle yes (with-eval-after-load 'gnus (load "oni-gnus-init")) #+END_SRC Configuring Gnus is actually configuring a handful of packages, so I require them all when Gnus is loaded so the byte compiler won't yell at me. #+BEGIN_SRC emacs-lisp (require 'gnus) (require 'gnus-msg) (require 'mail-source) (require 'message) (require 'nnfolder) (require 'sendmail) #+END_SRC I don't like having a lot of files spread around in my =.emacs.d= directory, so put all of Gnus', Message's and nnfolder's data in =.emacs.d/data=. #+BEGIN_SRC emacs-lisp (setq gnus-directory (locate-user-emacs-file "data/News") gnus-article-save-directory gnus-directory gnus-cache-directory gnus-directory gnus-kill-files-directory gnus-directory) (setq mail-source-directory (locate-user-emacs-file "data/Mail") message-directory mail-source-directory nnfolder-directory mail-source-directory) #+END_SRC Use msmtp to send my messages. #+BEGIN_SRC emacs-lisp (setq send-mail-function 'send-mail-send-it message-send-mail-function 'message-send-mail-with-sendmail sendmail-program "/usr/bin/msmtp") #+END_SRC I've been using Gnus for a while now and I don't think I fit the profile of a novice anymore. Turning this off will stop Gnus from asking me if I'm sure I want to delete a certain message, I do this a lot because expiring messages seems to take too long for my tastes. #+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 (defun oni-gnus-delete-forward (&optional n) "Delete the article under point and move to the next one. Do this N times." (interactive "p") (dotimes (_ (or n 1)) (gnus-summary-delete-article) (gnus-summary-next-subject 1))) (define-key gnus-summary-mode-map (kbd "M-d") #'oni-gnus-delete-forward) #+END_SRC Change the format of how each line for a group in the Group buffer is displayed. This shows the group name, the select method, group subscription status, the process mark (whatever that is), whether there is a summary buffer open for that group, number of unread articles and the number of ticked articles. #+BEGIN_SRC emacs-lisp (setq gnus-group-line-format "%P%(%20G%): %-10s %S%p%B %5y %5T\n") #+END_SRC *** Mail accounts I mostly use two email accounts. **** ryuslash.org Set my main email account as the primary select method for Gnus. #+BEGIN_SRC emacs-lisp (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 (add-to-list 'gnus-posting-styles '(".*" (address "tom@ryuslash.org") (eval (setq message-sendmail-extra-arguments '("-a" "ryuslash"))))) #+END_SRC **** gmail.com Add my other personal email as a secondary select method. #+BEGIN_SRC emacs-lisp (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 (add-to-list 'gnus-posting-styles '("gmail:" (name "Tom Willemse") (address "ryuslash@gmail.com") (eval (setq message-sendmail-extra-arguments '("-a" "gmail"))))) #+END_SRC ** Org mode :PROPERTIES: :header-args: :tangle "init/oni-org-init.el" :END: Since Org mode is a big package and I end up customizing it /a lot/ I always keep its settings in a separate file since it might be awhile before org-mode is loaded. #+BEGIN_SRC emacs-lisp :tangle yes (with-eval-after-load 'org (load "oni-org-init")) #+END_SRC To keep the byte-compiler from complaining, require any libraries that are used by my configuration when this file is loaded. #+BEGIN_SRC emacs-lisp (require 'org) (require 'org-bullets) (require 'org-capture) #+END_SRC Fontify source code blocks in Org mode natively, meaning that they should be fontified using the major mode specified in the source block language. #+BEGIN_SRC emacs-lisp (setq org-src-fontify-natively t) #+END_SRC Follow the link at point when {{{key(RET)}}} is pressed. #+BEGIN_SRC emacs-lisp (setq org-return-follows-link t) #+END_SRC Automatically fill paragraphs while editing text. #+BEGIN_SRC emacs-lisp (add-hook 'org-mode-hook 'auto-fill-mode) #+END_SRC Show pretty bullets instead of the default asterisk characters. #+BEGIN_SRC emacs-lisp (add-hook 'org-mode-hook 'org-bullets-mode) #+END_SRC ** Grep Make searching for "js" include ~*.js~, ~*.jsx~ and ~*.json~ files. #+BEGIN_SRC emacs-lisp (add-to-list 'grep-files-aliases '("js" . "*.js *.jsx *.json")) #+END_SRC Make searching for "css" include ~*.css~, ~*.less~, ~*.sass~ and ~*.scss~ files. #+BEGIN_SRC emacs-lisp (add-to-list 'grep-files-aliases '("css" . "*.css *.less *.sass *.scss")) #+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