dotfiles/emacs/.emacs.d/init.org

1616 lines
45 KiB
Org Mode

#+TITLE: Tom-Emacs Interface
#+STARTUP: content
#+MACRO: key @@html:<kbd>$1</kbd>@@@@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 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 {{{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
<?php
array(
'foo' => '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
Set the basic offset to 2 spaces for JavaScript.
#+BEGIN_SRC emacs-lisp
(setq js2-basic-offset 2)
#+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
* 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