It’s been said “there are many ways to skin a cat”. The same can be said of Emacs. Probably.
Don’t be shy - introduce yourself to emacs. If you are copying this config, make sure you use your name. We don’t want to confuse my mother.
(setq user-full-name "Alex Recker"
user-mail-address "[email protected]")
All packages are installed with the use-package library. Sadly, this needs to load before org can tangle anything, so all the action is in init.el.
Ensure that the system PATH
is the one used by emacs.
(use-package exec-path-from-shell
:ensure t
:config (exec-path-from-shell-initialize))
The slash screen displayed on startup is a little too noisy for
me. The *scratch*
buffer is a lot more low key.
(setq inhibit-startup-message 't)
With this function, we can randomize the *scratch*
message eachs
time using the output of a program.
(defun recker/get-startup-scratch ()
(with-temp-buffer
(lisp-mode)
(insert-string (shell-command-to-string recker/scratch-message-program))
(comment-region (point-max) (point-min))
(buffer-string)))
I like to use my very own wilfred-say, but the classic fortune
is a
good candidate as well.
(setq recker/scratch-message-program "wilfred-say")
(setq initial-scratch-message (recker/get-startup-scratch))
Make the *scratch*
buffer unkillable.
(use-package unkillable-scratch
:ensure t
:init (unkillable-scratch))
Start the emacs server if it is not running.
(require 'server)
(unless (server-running-p)
(server-start))
This allows you to connect to the emacs process from somewhere else - like a terminal session.
Emacs comes with some obnixious defaults. “Not on my watch!”, yelled Alex as he disabled them.
(setq make-backup-files nil
auto-save-default nil
indent-tabs-mode nil)
(global-auto-revert-mode 1)
(menu-bar-mode 0)
(scroll-bar-mode 0)
(tool-bar-mode 0)
(delete-selection-mode t)
I overwrite the build-in comment-dwim
with its superior sequel.
(use-package comment-dwim-2
:ensure t
:bind ("M-;" . comment-dwim-2))
Hide all minor modes from the modeline (since there are usually like a hundred).
(use-package rich-minority
:ensure t
:init (rich-minority-mode 1)
:config (setq rm-blacklist ""))
By default, hide dot files. They can be shown by disabling
dired-omit-mode
with C-x M-o
.
Another nice side effect of dired-x
is suddenly gaining the ability
of jumping to the current file in dired with C-x C-j
.
(require 'dired-x)
(setq-default dired-omit-files-p t)
(setq dired-omit-files (concat dired-omit-files "\\|^\\..+$"))
I use expand-region
to incrementally grab larger portions of text
based on where the cursor is. It’s a brilliant tool.
(use-package expand-region
:ensure t
:bind ("C-=" . er/expand-region))
Company mode.
(use-package company
:ensure t
:config (global-company-mode))
Yasnippet - I don’t use this nearly as much as I should be.
(use-package yasnippet
:ensure t
:init (yas-global-mode 1))
Completion and filtering with ivy, supported by counsel.
(use-package ivy
:ensure t
:config (setq ivy-use-selectable-prompt t)
:init (ivy-mode 1))
(use-package counsel
:ensure t
:bind
("C-c i" . counsel-imenu)
("C-c s" . swiper)
("C-x C-y" . counsel-yank-pop))
Spartparens - because I can’t even be bothered to close my own parentheses and quotes.
(use-package smartparens
:ensure t
:init (progn (smartparens-global-mode t)
(sp-pair "'" nil :actions :rem)))
Magit. Seriously. Just try it you heathen.
(use-package magit
:ensure t
:bind ("C-x g" . magit-status))
These are the settings for various editing modes - the top level being
text-mode
, which is for “editing text written for humans to read”.
(defun recker/text-mode-hook ()
(auto-fill-mode 1)
(flyspell-mode 1)
(flymake-mode-off))
(add-hook 'text-mode-hook 'recker/text-mode-hook)
Flycheck mode.
(use-package flycheck
:ensure t
:init
(global-flycheck-mode))
Globally cleanup white space on save.
(use-package whitespace-cleanup-mode
:ensure t
:config (global-whitespace-cleanup-mode))
Use pretty symbols where possible.
(global-prettify-symbols-mode t)
Support for editorconfig.
(use-package editorconfig
:ensure t
:config (editorconfig-mode 1))
For this to work, sbcl should be installed and in PATH
.
(use-package slime
:ensure t
:config (setq inferior-lisp-program (executable-find "sbcl")))
(use-package slime-company
:ensure t
:init (slime-setup '(slime-fancy slime-company)))
(use-package csv-mode
:ensure t
:mode "\\.csv\\'")
(use-package dockerfile-mode
:ensure t
:mode "\\Dockerfile\\'")
Disable those silly docstring warnings when editing elisp.
(with-eval-after-load 'flycheck
(setq-default flycheck-disabled-checkers '(emacs-lisp-checkdoc)))
Pretty much just for Jenkins files.
(use-package groovy-mode
:ensure t
:mode "\\Jenkinsfile\\'")
(use-package web-mode
:ensure t
:mode ("\\.html\\'" "\\.jinja\\'")
:config (setq web-mode-markup-indent-offset 2
web-mode-code-indent-offset 2))
(use-package emmet-mode
:ensure t
:config (add-hook 'web-mode-hook 'emmet-mode))
This is the web-scale portion of my config.
(setq js-indent-level 2)
(use-package markdown-mode
:ensure t
:commands (markdown-mode gfm-mode)
:mode (("README\\.md\\'" . gfm-mode)
("\\.md\\'" . markdown-mode)
("\\.markdown\\'" . markdown-mode))
:init (setq markdown-command "pandoc"))
Install these dependencies
pip install --user rope flake8 importmagic autopep8 yapf ipdb ipython virtualenv virtualenvwrapper
Install virtualenvwrapper support.
(use-package virtualenvwrapper
:ensure t)
Use ipython for running the code in a shell. Evidently, it’s still
experimental. I have issues with some of the tab completion, so I’ll
end up using *ansi-term*
instead.
(setq python-shell-interpreter "ipython"
python-shell-interpreter-args "-i --simple-prompt")
Let elpy do its thing.
(use-package elpy
:ensure t
:init (elpy-enable))
These are very much a work in progress. I know about as much about ruby as I know about scented candles and professional football.
(setq ruby-deep-indent-paren nil)
(use-package terraform-mode
:ensure t
:mode "\\.tf\\'")
I’m a simple man, and I use a simple shell.
(defun recker/ansi-term ()
(interactive)
(ansi-term "/bin/bash"))
(global-set-key (kbd "C-c e") 'eshell)
(global-set-key (kbd "C-x t") 'recker/ansi-term)
The terminal buffer should be killed on exit.
(defadvice term-handle-exit
(after term-kill-buffer-on-exit activate)
(kill-buffer))
Aliases for eshell
(defalias 'ff #'find-file)
(use-package indent-guide
:ensure t
:init (add-hook 'yaml-mode-hook 'indent-guide-mode))
(use-package yaml-mode
:ensure t
:mode ("\\.yml\\'" "\\.sls\\'")
:init
(add-hook 'yaml-mode-hook 'turn-off-auto-fill))
Org is love. Org is life.
(use-package ob-http :ensure t)
(use-package ob-browser :ensure t)
(use-package org
:ensure t
:config (progn (setq org-hide-emphasis-markers t)
(custom-set-faces ;Get rid of the different font sizes on headers
'(org-document-title ((t (:inherit outline-1 :height 1.0 :underline nil))))
'(org-level-1 ((t (:inherit outline-1 :height 1.0))))
'(org-level-2 ((t (:inherit outline-2 :height 1.0))))
'(org-level-3 ((t (:inherit outline-3 :height 1.0))))
'(org-level-4 ((t (:inherit outline-4 :height 1.0))))
'(org-level-5 ((t (:inherit outline-5 :height 1.0))))))
:init (org-babel-do-load-languages
'org-babel-load-languages
'((awk . t)
(browser . t)
(C . t)
(calc . t)
(clojure . t)
(css . t)
(ditaa . t)
(ditaa . t)
(haskell . t)
(http . t)
(java . t)
(js . t)
(latex . t)
(lisp . t)
(makefile . t)
(perl . t)
(python . t)
(ruby . t)
(scala . t)
(screen . t)
(sh . t)
(sql . t)
(sqlite . t))))
This package gives the ability to export documents in that wonky fake markdown that Atlassian invented.
(use-package ox-jira :ensure t)
Use this package to make source pretty. Or just leave the CSS classes in case I want to add a theme some day.
(use-package "htmlize"
:ensure t
:config (setq org-html-htmlize-output-type 'css))
Gnus has a steep learning curve, and learning to incorporate this mysterious program has proven to be an emotional roller coaster. I’m not even sure I know enough about it to say “it’s worth it”, but hopefully this will help you with your own journey.
Gnus requires a “primary method” from which you obtain news. Unfortunately, the program kind of explodes if this isn’t set, which proves to be kind of a pain when you want to poke around and set up things interactively.
Here’s my workaround - set the primary method to a dummy protocol that will immediately come back. In our case, this is a blank nnml stream.
(setq gnus-select-method '(nnml ""))
Default on topic mode, since it’s more helpful.
(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)
Disable saving to a newsrc
config file.
(setq gnus-save-newsrc-file nil)
Read the auto save file on startup without asking.
(setq gnus-always-read-dribble-file t)
Gnus creates a bunch of folders in your home directory that, as far as
I can tell, are not needed outside of gnus. These settings will hide
them all in ~/.gnus
, which will serve as our convenient nuke-point
if things ever go south while playing around.
Yes - nnfolder-directory is really needed. Whether this is a bug or not, the redundancy is intentional.
(setq gnus-home-directory "~/.gnus"
nnfolder-directory "~/.gnus/Mail/archive"
message-directory "~/.gnus/Mail"
nndraft-directory "~/.gnus/Drafts")
Use gmane and gwene to follow news, mailers, and tons of other syndicated things. There are even comics.
(setq gnus-secondary-select-methods '((nntp "news.gmane.org")
(nntp "news.gwene.org")))
Add a personal IMAP account.
(add-to-list 'gnus-secondary-select-methods
'(nnimap "personal"
(nnimap-address "imap.gmail.com")
(nnimap-server-port "imaps")
(nnimap-stream ssl)
(nnmail-expiry-target "nnimap+gmail:[Gmail]/Trash")
(nnmail-expiry-wait immediate)))
Posting styles for a personal email.
(setq gnus-posting-styles '((".*" (signature (string-join '("Alex Recker" "[email protected]") "\n")))))
Don’t attempt to archive outbound emails to groups.
(setq gnus-message-archive-group nil)
Keep addresses locally using bbdb
.
(use-package bbdb
:ensure t
:config (setq bbdb-file "~/.bbdb")
:init
(bbdb-mua-auto-update-init 'message)
(setq bbdb-mua-auto-update-p 'query)
(add-hook 'gnus-startup-hook 'bbdb-insinuate-gnus))
The rest of the configuration can be set up interactively. Just open
a message buffer and hit C-c C-c
. Emacs will allow you to choose a
delivery method, enter your credentials, and even save everything.
To encrypt your credentials, just save it within ~/.authinfo.gpg
.
These are miscellaneous functions that I’ve written (or plagiarized).
(defun recker/purge-buffers ()
"Delete all buffers, except for *scratch*."
(interactive)
(mapc #'(lambda (b) (unless (string= (buffer-name b) "*scratch*") (kill-buffer b))) (buffer-list)))
(defun recker/unfill-region (beg end)
"Unfill the region, joining text paragraphs into a single logical line."
(interactive "*r")
(let ((fill-column (point-max)))
(fill-region beg end)))
(defun recker/org-scratch ()
"Open a org mode *scratch* pad."
(interactive)
(switch-to-buffer "*org scratch*")
(org-mode)
(insert "#+TITLE: Org Scratch\n\n"))
(global-set-key (kbd "C-c b") 'browse-url)
(global-set-key (kbd "C-x k") 'kill-this-buffer)
(global-set-key (kbd "C-x C-k k") 'kill-buffer)
(global-set-key (kbd "C-c f") 'project-find-file)
(global-set-key (kbd "C-c l") 'sort-lines)
(global-set-key (kbd "C-c o") 'recker/org-scratch)
(global-set-key (kbd "C-c r") 'replace-string)
Emacs sometimes dumps things in init.el
. It means well, but I would
rather this be in a different file ignored by git.
(let ((custom (concat (file-name-as-directory user-emacs-directory) "custom.el")))
(unless (file-exists-p custom)
(with-temp-buffer
(write-file custom)))
(setq custom-file custom))
I also like to keep a file around for miscellaneous elisp that should run on startup. This is for machine specific settings or things I am still tinkering with.
(let ((local (concat (file-name-as-directory user-emacs-directory) "local.el")))
(unless (file-exists-p local)
(with-temp-buffer
(insert ";; This file is for local changes")
(write-file local)))
(load local))