1
0
Fork 0

Initial literate Emacs config

I have been sitting on this for a while (since it is incomplete), but this
is the majority of my Emacs configuration.  I have been using Emacs for less
than a year, and have been astounded by the flexibility afforded by its
implementation of most functionality in Lisp.

Plenty more to come.
org
Mike Gerwitz 2015-07-07 23:07:23 -04:00
parent 786c1099ff
commit 9ec0bea609
No known key found for this signature in database
GPG Key ID: F22BB8158EE30EAB
2 changed files with 1056 additions and 0 deletions

920
emacs.d/emacs.org 100644
View File

@ -0,0 +1,920 @@
#+TITLE: Mike Gerwitz's Emacs Configuration
#+AUTHOR: Mike Gerwitz
#+EMAIL: mtg@gnu.org
* Introduction
This is my personal Emacs configuration. It is written in a [[http://www.literateprogramming.com/][literate]]
style; this file serves as both a document and the configuration
source code.
This is a work-in-progress; I am still relatively new to Emacs (I have
been using Vim for over a decade, and Emacs only since late
2014). But even so, there's a lot here; you'd be surprised how quickly you
can accumulate configuration options and actual code to customize
Emacs. And that really speaks to its flexibility and appeal to developers:
nearly everything is written in lisp, and nearly everything can be changed,
often at runtime. The amount of customization the average Emacs user
performs does not mean that Emacs is too complicated or does a poor job at
configuration.
Contract this to my Vim configuration, which struggles to even reach 200
lines after over a decade (but I do use a number of plugins). There's
beauty in that too.
Please forgive any atrocities that could be handled more elegantly or
efficiently (and send me a patch!).
** Lexical Binding
All variables in this file are lexically bound---that is, they are
bound to the scope of the containing expression rather than being
defined globally. This is what you would expect from most sane
languages, such as Scheme.
#+BEGIN_SRC emacs-lisp :padline no
;; -*- lexical-binding: t -*-
#+END_SRC
** Word of Warning
Do not edit the generated file. It will be overridden during
re-tangling.
#+BEGIN_SRC emacs-lisp
;;;
;;; WARNING: This source file is the tangled output
;;; of init.org; do not modify!
;;;
#+END_SRC
* General Settings
** Package Archives
These are the archives from which I may download packages. This will
be refined as I explore them in more detail.
#+BEGIN_SRC emacs-lisp
(setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/")
("org" . "http://orgmode.org/elpa/")
("marmalade" . "http://marmalade-repo.org/packages/")
("melpa" . "http://melpa.milkbox.net/packages/")))
#+END_SRC
Packages installed from the archives are initialized simply:
#+BEGIN_SRC emacs-lisp
(package-initialize)
#+END_SRC
** Bookmarks
If I take the time to save my position in a buffer, I would prefer that I do
not lose that information. Setting =bookmark-save-flag= will automatically
save after each modification.
#+BEGIN_SRC emacs-lisp
(setq bookmark-save-flag 1)
#+END_SRC
* User Interface
The editor is my canvas. That may sound corny, but I'm looking at
this thing for a good part of every day of my life; it needs to be
pleasing to both the eyes and the fingers. If returning to your
editor---buffers open and waiting; cursor beckoning---is not
titillating, then your editor is either misconfigured or not for
you. (Or maybe you don't care, which is really a shame.)
** <<<Evil Mode>>>
Evil mode is an extensible vi layer for Emacs. I have always
been attracted to a number of Emacs features, most notably its use of
a Lisp dialect. The barrier was its keybindings, which are inferior
to those of Vim.
A combination of the two, however, is potent.
Evil has since grown into an excellent project that provides a
surprisingly strong Vim-like experience in Emacs. There are some
rough edges, and not all things are wholly consistent, but development
continues and I will continue to submit patches to help things along.
Since I both track updates to the project, and make my own
modifications, I load Evil from a local repository.
#+BEGIN_SRC emacs-lisp
(add-to-list 'load-path "~/gitrepos/evil-mtg")
#+END_SRC
Before loading evil mode: the default is to leave the default Emacs =C-u=
keybinding, which is =universal-argument=; this is very inconvenient, since
I use =C-u= very frequently, which is =PgUp= (=<prior>=) in Vim.
#+BEGIN_SRC emacs-lisp
(setq evil-want-C-u-scroll t)
(require 'evil)
(evil-mode t)
#+END_SRC
*** Suspending Emacs
Evil overrides =C-z=, for whatever perverted reason, to enter "Emacs"
mode rather than suspending Emacs. I do not like this
behavior. Instead, I have =C-z= in Normal mode continue to suspend
Emacs. In Insert mode, however, it retains Evil's functionality and
enters "Emacs" mode; this makes sense, I think, because Emacs is
similar to Insert mode in that most keybindings echo.
#+BEGIN_SRC emacs-lisp
(evil-define-key 'normal global-map
;; note that you can still return to Emacs mode in insert mode
"\C-z" 'suspend-emacs)
#+END_SRC
** UI Stripping
The first thing that a new (or unconfigured) user encounters is the
splash screen. It provides little value to an experienced user and is
annoying.
#+BEGIN_SRC emacs-lisp
(setq inhibit-splash-screen t)
#+END_SRC
I am accustomed to the beautifully simple interface of Vim---which I
have used exclusively for over a decade. Therefore, I strip the
text-mode UI (and the GUI) of annoyances such as the menu bar.
#+BEGIN_SRC emacs-lisp
(menu-bar-mode -1)
(tool-bar-mode -1)
#+END_SRC
I do not use the Emacs GUI---I am fond of the command line and a
terminal does just fine. This also fits well into my use of GNU
screen and SSH, allowing me to re-attach to remote sessions with
ease. But in the event that it happens to load (maybe the 'nox'
package was not installed), or I choose to load it, I want it to be as
consistent with the texi-mode UI as possible.
#+BEGIN_SRC emacs-lisp
(when (display-graphic-p)
(scroll-bar-mode -1)
(fringe-mode 0)
(tooltip-mode -1)
(use-diablog-box nil)
(add-to-list 'default-frame-alist
'(font . "DejaVu Sans Mono-7")))
#+END_SRC
** Layout
Your window layout defines how you perceive and interact with a
significant portion of your virtual world. It provides a physical
presence to the content of this virtual world, defining where in the
physical world it is rendered. Humans have a place for most things in
their environment; I see no difference here.
*** Window Height
I open a lot of files in my editor in a single session (which I leave
running as long as my screen session remains running, which is usually
until the box is rebooted, which is quite rare). In Vim, I would
manage this with a generous number of splits spread across various
tabs. Spacial orientation is important for me (allowing a file to
"live" in a certain location in the physical world) and offers a
number of benefits, so I produce a number of vertical splits (as much
as six, depending on the resolution, but I find that four is a sweet
spot), and numerous horizontal splits within them. I then "focus" on
a window within the split by maximizing its height to the available
space; in Vim, I set the minimum window height to =0=, so this shrinks
all other windows in the vertical split down to their status/mode
lines.
I do it often enough that I have a shortcut for doing so:
#+BEGIN_SRC emacs-lisp
(defun evil-window-select-expand (direction)
"Select window in DIRECTION and expand to fill available frame height"
(windmove-do-window-select direction)
(evil-window-set-height nil))
;; move up/down a window and expand to full height
(mapc #'(lambda (assoc)
(eval `(evil-define-key 'normal global-map
,(car assoc)
(lambda ()
(interactive)
(evil-window-select-expand ,(cdr assoc))))))
'(("\C-k" . 'up)
("\C-j" . 'down)))
#+END_SRC
Unfortunately, Emacs' default behavior prohibits a zero-height
window: =window-min-height= respects =window-safe-min-height=, which
defaults to =1=. Changing the latter to =0= will cause the first
visible line in the window to render, but the mode line is not
rendered. I'll explore changing the rendering logic in the future;
for now, I will live with a minimum window height of =1=.
#+BEGIN_SRC emacs-lisp
(setq window-min-height 1)
#+END_SRC
*** Minibuffer Height
The minibuffer (displayed at the very bottom of the editor when
invoking a command, for instance) is able to display multiple lines of
text. The default behavior is to allow the minibuffer to grow in
height, but not return to its original height as its content shrinks
(e.g. erasing newlines); this is annoying to me, and prods at my
[minor] OCD.
The better behavior is to resize to fit the contents, always.
#+BEGIN_SRC emacs-lisp
(setq resize-mini-windows t)
#+END_SRC
*** Window Layout Undo/Redo
It should be obvious from the previous sections that I would be rather
displeased if my window layout were to be disrupted, since that could
easily destroy months of accumulating buffers and layout
organization. This could happen for a number of reasons, including my
unfamiliarity with Emacs, me fat-fingering keys, or rude packages
modifying the layout and not restoring it.
Winner Mode is packaged with Emacs since version 20. It allows you to
undo and redo layout changes using =C <LEFT>= and =C <RIGHT>=.
#+BEGIN_SRC emacs-lisp
(winner-mode)
#+END_SRC
I have saved myself many times using this package.
*** Frames
In Vim, I made aggressive use of tabs to organize my many splits into
coherent groups. When I first moved to Emacs, this made for an
awkward transition: Emacs has a concept of frames, and they are not
rendered like tabs (at least not without help). On the CLI, with the
default behavior, you wouldn't even be able to tell that they exist.
To my surprise, I ended up finding Emacs' frames to be superior to
Vim's tabs. I'll write more about that when I get the chance.
**** Cycling Frames
Vim cycles tabs using =gt= (next tab) and =gT= (previous tab). Since
I do not display frames as tabs, this is admittedly of limited use to
me when I have a large number of frames open; however, it can still be
useful under certain circumstances.
#+BEGIN_SRC emacs-lisp
(evil-define-key 'normal global-map
"gt" 'other-frame
"gT" (lambda (n)
(interactive "p")
(other-frame (- n))))
#+END_SRC
**** Selecting Frame By Name
One powerful feature that Vim lacks (without a plugin) is the ability
to name tabs, which becomes important when you (ab)use them the way I
do. Emacs has this support built-in; you can set frame names with
=set-frame-name=. The frame name is displayed, by default, in the
mode line before the filename.
This means that we can select a frame using its name rather than its
position in the ring (like Vim). Emacs provides no default keybinding
for =select-frame-by-name=, so I provide my own:
#+BEGIN_SRC emacs-lisp
(evil-define-key 'normal global-map
"\C-w/" 'select-frame-by-name)
#+END_SRC
**** Switching Between Two Frames
I often find myself switching between two frames during
development. Reasons vary, but two projects may be strongly related
or concurrently developed; a single project may be organized into
separate frames for spacial recognition; I may be suffering from
context switching due to work on multiple, different projects;
etc. The two frames could be wholly arbitrary. Switching between
them can be frustrating, even with the minimal work of typing =C-x b
...= with autocompletion. That frustration makes switching a
displeasure, which means that something is wrong with my editor
configuration.
#+BEGIN_SRC emacs-lisp
(defun select-prev-frame-name ()
(interactive)
(let ((name (cadr frame-name-history)))
(if name
(progn
(select-frame-by-name name)
(setq frame-name-history
(cons name frame-name-history)))
(user-error "No previous frame"))))
#+END_SRC
=select-prev-frame-name= uses Emacs' built-in =frame-name-history= to
determine the name of the previously visited frame and raise it. I
bind this for convenience:
#+BEGIN_SRC emacs-lisp
(evil-define-key 'normal global-map
"\C-w," 'select-prev-frame-name)
#+END_SRC
** Minibuffer
*** Icomplete
=icomplete-mode= provides a massive increase in life expectancy for
Emacs users by doing its best to provide suggestions for command
completion in the minibuffer. You should use it.
#+BEGIN_SRC emacs-lisp
(icomplete-mode)
#+END_SRC
*** Recursive Buffers
The default behavior of Emacs does not permit recursive
minibuffers---that is, minibuffer commands while within a
minibuffer. It's too arbitrary of a restriction for me, and is
something that occasionally comes in handy.
#+BEGIN_SRC emacs-lisp
(setq enable-recursive-minibuffers t)
#+END_SRC
** Mode Line
Emacs users do some pretty kinky stuff with their mode lines, especially in
graphical environments. I don't do much of anything at the moment (most of
my useful information is part of my GNU screen hardstatus line).
*** Point Column
I do want to know the column position of point; this is useful for a variety
of things, including observing line length and column numbers for error
messages. In the case of the latter, I normally use the Vim
(Evil-supported) command =N|=, which takes me to column =N=, but having the
column number in the mode line allows me to verify that I didn't fat-finger
the number.
#+BEGIN_SRC emacs-lisp
(column-number-mode 1)
#+END_SRC
** Scrolling
The first order of business is to get scrolling into a sane state with
evil mode. In particular, the use of =C-u= to scroll up.
Emacs uses =C-u= as a command modifier. Since evil mode allows
the use of Emacs commands, it retains this key binding by
default. Fortunately, this can be corrected with a simple
configuration value:
#+BEGIN_SRC emacs-lisp
(setq evil-want-C-u-scroll t)
#+END_SRC
*** <<<Scroll Margin>>>
It is useful to be able to see lines of text that surround point; this
allows scanning without having to move point or scroll the window,
which is slower than moving your eyeballs, and is more
distracting. Having point at the very first or last line of a window
also makes me feel a bit uncomfortable---like having no peripheral
vision. It also helps to visually state, without looking at the mode
line, whether the window has reached the end of the buffer.
We do not want too much of a scroll margin (as it is called), since
that would reduce the effective amount of lines visible on the screen
during editing---if wanted to edit the last line in a window, and the
scroll margin was $n$, then I'd lose $n$ lines at the top when I
scroll to it. Further, using =evil-window-bottom= (=L= in Normal
mode) takes into account the scroll margin, meaning the last $n$ lines
of the window are not as easily accessible. Similar arguments can be
made for =evil-scroll-line-to-bottom= (=zb= in Normal mode) and
others.
All of that said, I have found a three-line scroll margin to treat me
well over the years.
#+BEGIN_SRC emacs-lisp
(setq scroll-margin 3)
#+END_SRC
*** Tracking Point
<<<sec:tracking-point>>>
When point moves off of the screen, the default Emacs behavior is to
re-center point in the window at that line. This is odd to me, but
perhaps because it's not something that I am used to happening; the
sudden jump of such a large amount of text (considering modern
resolutions and my terminal font size) disrupts me.
Instead, the window should scroll just enough to keep point on the
screen, subject to the scroll margin.
#+BEGIN_SRC emacs-lisp
(setq scroll-conservatively 1)
#+END_SRC
*** Recentering
There are other operations (in addition to [[sec:tracking-point][tracking point]]) that cause
point to be recentered. The default behavior on a TTY is to redraw
the entire frame when this occurs, possibly to cater to buggy
VTEs. This is highly undesirable for me---it is both a performance
issue and terrible eye sore due to my high terminal
resolution. Fortunately, this behavior can be disabled.
#+BEGIN_SRC emacs-lisp
(setq recenter-redisplay nil)
#+END_SRC
In the rare instances where redrawing is actually an issue, there is
always =redraw-display=.
** <<<Line Numbering>>>
Line numbering is useful for eyeballing text when line numbers are
referenced (e.g. error messages when compiling source code), for
getting an idea of where you are in a file, peer programming, and
other things. I have used line numbers for over a decade. They are
not enabled by default in Emacs (or Vim/vi).
I originally used <<<linum mode>>> for line numbering, but found that
it was far too slow due to my large terminal resolution. So, I gave
<<<nlinum mode>>> a try; this was much faster, but was still a
bottleneck. So I wrote a more strongly optimized procedure to handle
rendering:
#+BEGIN_SRC emacs-lisp
;; line numbering (we ignore nlinum-format for performance)
(setq nlinum-format-function
(lambda (line width)
(let ((str (concat (number-to-string line) " ")))
(when (< (length str) width)
;; Left pad to try and right-align the line-numbers.
(setq str (concat (make-string (- width (length str)) ?0)
str)))
(put-text-property 0 width 'face 'linum str)
;; FIXME: this relies on the fact that the format has a
;; trailing space
(put-text-property (1- width) width 'face 'hidden str)
str)))
#+END_SRC
That helped considerably. But I was still left disappointed by
profiler results when trying to determine slowdowns.
As it turns out, I don't need line numbers; I've been experimenting
with leaving line numbers disabled, and things have been going well;
my eyes are adjusting moving to the mode line if I need the line
number, and I find that it's rare that I even need that. For
instance, if I need to visit a particular line, I enter the line
number, not scroll to it.
I will, however enable nlinum mode in peer programming situations or
code review, since it facilities discussion.
** Sentences
<<<Sentence mode>>> is a minor mode that will highlight the entire
sentence under point. I find this useful not only as a reading aid,
but also compositionally---it allows me to see the length of sentences
in my work and points out suspicious sentences that may be run-ons;
yada. I use semi-colons aggressively in my written works as well, so
sentence highlighting consequently highlights groups of ideas.
#+BEGIN_SRC emacs-lisp
(require 'sentence-highlight)
#+END_SRC
See [[sec:mode-hooks][Mode Hooks]] for major modes making use of this minor mode.
** Errors
The command =]e= is analogous to =]s= below. A negative numeric argument
can be used to cause =next-error= to go back, but a Vim-like =]e= is still
provided for convenience.
#+BEGIN_SRC emacs-lisp
(evil-define-key 'normal global-map
"]e" 'next-error
"[e" (lambda (&optional arg reset)
(interactive "P")
(next-error (- (prefix-numeric-value arg))
reset)))
#+END_SRC
*** Spell Checking
Vim's spell checking keybindings are useful. Unfortunately, I have not yet
put the time into a solution for =[s=; =flyspell-goto-previous-error= does
not exist and =flyspell-goto-next-error= is not written such that this is
easy to do. =flyspell-check-previous-highlighted-word= searches backwards,
but then invokes spelling correction, which is not desirable. A solution
will likely involve Flyspell refactoring and a patch.
#+BEGIN_SRC emacs-lisp
(evil-define-key 'normal global-map
"]s" 'flyspell-goto-next-error)
#+END_SRC
** Hidden Content
When modes permit customization via faces, it is sometimes useful to
be able to hide text entirely.
#+BEGIN_SRC emacs-lisp
(defface hidden '((t (:foreground nil :background nil)))
"Hide text")
#+END_SRC
* <<<Session>>>
Session management allows you to continue where you left off at an
earlier point in time, usually restoring buffers, windows, frames, and
other configuration options. This is especially important for myself,
since I use (usually) a single Emacs session with many hundreds of
buffers, a dozen or more frames (each [[sec:frame-name][named]]), and often dozens of
windows per frame, spatially memorized. I simply cannot afford to
lose such a session.
Session saving is provided by Emacs' built-in <<<desktop mode>>>.
#+BEGIN_SRC emacs-lisp
(setq desktop-restore-frames t
desktop-resture-in-current-display t
desktop-restore-forces-onscreen nil)
#+END_SRC
To ensure that no information is lost, I save desktop sessions on [[sec:version-control][auto-save]]:
#+BEGIN_SRC emacs-lisp
(add-hook 'auto-save-hook
'desktop-save-in-desktop-dir-quiet)
#+END_SRC
The =-quiet= suffix there is to ensure that saving does not produce errors
if we are not the owner of the session:
#+BEGIN_SRC emacs-lisp
(defun desktop-save-in-desktop-dir-quiet ()
(interactive)
(if (eq (desktop-owner) (emacs-pid))
(desktop-save desktop-dirname)))
#+END_SRC
** Saving Session Frame Names
<<sec:frame-name>>
I am unsure why the default is to not save frame names (it may have
simply been overlooked; I should probably ask), but that is deeply
frustrating due to the number of frames that I maintain. Fortunately,
it is an easy problem to solve:
#+BEGIN_SRC emacs-lisp
;; this first line is suggested by the frameset-filter-alist docs
(setq frameset-filter-alist (copy-tree frameset-filter-alist))
(add-to-list 'frameset-filter-alist
'(name . nil))
#+END_SRC
** Command History
Have you ever been in a situation where you know you did something a
number of days ago, but you don't remember exactly how you did it? Of
course!
My shell history length is quite large, but I don't think that such is
necessary with Emacs, since most commands issued to Emacs are not
=M-x=-commands.
#+BEGIN_SRC emacs-lisp
(setq history-length 1024)
#+END_SRC
* Files and <<<Version Control>>>
<<<sec:version-control>>>
** Backups
With modern source code management systems, old-school version control
using backups following a naming convention are not often
needed. That said, there are two particular cases where it is still
valuable: for files that are not [yet] under version control, or as a
save-my-ass feature in the event that work had not been committed.
#+BEGIN_SRC emacs-lisp
(setq version-control t
backup-directory-alist '(("." . "~/tmp/"))
auto-save-file-name-transforms '((".*" "~/tmp/" t))
kept-new-versions 100
kept-old-versions 20
delete-old-versions t)
#+END_SRC
On a similar note, Emacs creates lock files by default---they are
intended to prevent users from concurrently editing the same file
using Emacs (or any other editor that checks for the lock). Since all
my shared editing is done via a VCS, this does nothing but create
annoying files.
#+BEGIN_SRC emacs-lisp
;; not defined until Emacs 24.3
(setq create-lockfiles nil)
#+END_SRC
** Reverting
Emacs' concept of "reverting" involves discarding changes in a buffer and
loading the contents of its respective file from disk. Most editors have
some sort of facility for handling this type of situation, as it is an
important one: overwriting a file with changes to an out-of-date version
risks clobbering data. Emacs does, fortunately, prompt in such a situation.
When working with version control systems---namely Git, in my
situation---switching branches may yield file changes. I switch branches
regularly, and it is important that my editor reflects those (often vast)
changes; waiting until I have already made modifications to a file before
discovering that it has changed is unacceptable.
#+BEGIN_SRC emacs-lisp
(global-auto-revert-mode)
#+END_SRC
* Mode Hooks and Configuration
<<<sec:mode-hooks>>>
Here I define all the minor modes that shall be enabled when the
corresponding major mode(s) take effect.
#+BEGIN_SRC emacs-lisp
(defun disable-mode-fn (mode)
"Return function to disable `MODE'"
(lambda ()
(if (boundp mode)
(funcall mode -1)
(warn (concat
"disable-mode-fn: unknown mode: "
(symbol-name mode))))))
(defconst my-mode-hooks
`((turn-on-auto-fill . (text-mode-hook
prog-mode-hook))
;; perf issues
;; (fci-mode . (prog-mode-hook))
;; highlight lines (no global mode, since that makes disabling
;; it per-buffer a PITA)
(hl-line-mode . (text-mode-hook
prog-mode-hook))
(show-paren-mode . (prog-mode-hook))
(electric-pair-mode . (prog-mode-hook))
(which-function-mode . (prog-mode-hook))
(flyspell-prog-mode . (prog-mode-hook))
(js2-mode . (js-mode-hook))
(flyspell-mode . (text-mode-hook))
(whitespace-mode . (text-mode-hook
prog-mode-hook))
;; skimpy tabbing
(,(apply-partially 'set-tab-width 2) . (shell-mode-hook
nxml-mode-hook))
;; knock it off prog modes
(,(apply-partially 'set-fill-column 76) . (prog-mode-hook))
(sentence-highlight-mode . (text-mode-hook))
;; these modes do not cooperate with electric-pair-mode
(,(disable-mode-fn 'electric-pair-mode) . (nxml-mode-hook))
;; flyspell is too much atop of the slow nxml processing
(,(disable-mode-fn 'flyspell-mode) . (nxml-mode-hook))
;; FIXME: until I can figure out a consistent solution to face
;; precedence; it highlights whitespace in its own face, unless you load
;; whitespace-mode after it, so we'll get rid of it for now
(,(disable-mode-fn 'whitespace-mode) . (message-mode-hook))
;; no line highlighting in terminals
(,(disable-mode-fn 'hl-line-mode) . (term-mode-hook))
;; nxml's parent mode is text-mode, but I treat it more like a
;; programming language
(,(disable-mode-fn 'sentence-highlight-mode) . (nxml-mode-hook)))
"List of pairs defining functions to be applied to hooks
The purpose of this is to be able to determine, at a glance, all modes to
which the given function or minor mode apply. It is trivial to see the
reverse by inspecting the runtime value of those hooks.")
;; apply mode hooks
(mapc (lambda (pair)
(let ((f (car pair))
(modes (cdr pair)))
(mapc (lambda (mode)
(add-hook mode f t))
modes)))
my-mode-hooks)
#+END_SRC
** File Extensions
#+BEGIN_SRC emacs-lisp
(add-to-list
'auto-mode-alist
'("\\.md\\'" . markdown-mode))
#+END_SRC
** Ediff
Most modern resolutions are wide-screen; that is the case for me, even on my
laptop. The name =split-window-horizontally= is deceptive: it's what is
more often referred to in other software as a "vertical split": two
side-by-side windows.
#+BEGIN_SRC emacs-lisp
(setq ediff-split-window-function
'split-window-horizontally)
#+END_SRC
** JavaScript
=js-mode='s indentation strategy is abhorrent.
#+BEGIN_SRC emacs-lisp
(add-hook 'js-mode-hook
(lambda ()
(setq indent-line-function 'indent-relative)))
#+END_SRC
* Editing
I'm told that Emacs is an operating system. I'm also told that it is
an editor. I've been convinced of both.
** <<<Fill Column>>> (<<<Line Length>>>)
The /fill column/ determines what column line wrapping should occur
beyond. The default value is 70. In general, I'm okay with this, but
it deserves a bit of discussion. Line length is one of those
religious debates that nobody will win. But I can tell you why many
hackers and technical people tend toward smaller line lengths, and why
I choose the lengths that I do.
/TODO; I don't have the time for my line-length dissertation right now./
My default line length is 76. My rationale:
- Standard Unix terminal column size of 80;
- Minus three characters (reasonable) for line numbering (77);
- Minus another character to delimit line number from text (76).
Further, the above also allows for (without line numbering) up to
three levels of nested quotes using the standard block quote delimiter
(">"; see [[#Replying][Replying (to mail)]]).
#+BEGIN_SRC emacs-lisp
(setq-default fill-column 76)
#+END_SRC
That is not always an appropriate default, though; I may override it
for other modes. See also [[#Mode%20Hooks][Mode Hooks]].
** Whitespace
Various types of whitespace are important to recognize. With a
fixed-width font (which, if you're reading this document, you should
be using!), we don't have to worry so much about the number of spaces
between printable characters, since that can be fairly well
eye-balled. But leading and trailing whitespace are of particular
importance.
Leading whitespace is used for indentation, and is generally either
tabs or spaces. Distinguishing between the two is vital for
consistency, and sometimes semantically (e.g. Makefiles' need for
tabs in recipes). Trailing whitespace is almost always a bad thing,
so that should be made apparent. Newlines can be recognized by, well,
a line break.
#+BEGIN_SRC emacs-lisp
(setq-default
whitespace-style '(face
spaces
tabs
newline
space-mark
tab-mark
trailing))
#+END_SRC
/TODO: How do I address Unicode NBR? Carriage returns?/
*** Tab Width and Stops
It is important to respect others' whitespace decisions; if tabs already
exist, then they should be retained. Certain languages (e.g. Make) also
assign meaning to tab characters.
But just setting the tab width is not enough; in Emacs, the act of tabbing
is governed by tab stops. I therefore define =set-tab-width= to both set
the tab width for display of the tab character and to generate the proper
=tab-stop-list=:
#+BEGIN_SRC emacs-lisp
(defun set-tab-width (width)
"Set tab width to WIDTH and generate tab stops"
(setq tab-width width)
(setq tab-stop-list
(number-sequence width 120 width)))
#+END_SRC
I use this primarily in [[sec:mode-hooks][mode hooks]], but I do generally prefer a default of
four characters:
#+BEGIN_SRC emacs-lisp
(set-tab-width 4)
#+END_SRC
*** Indentation
One thing that really annoys me is when my editor tries to be too smart:
especially about something like indentation, which is so precise and
variable. There are certain languages with strong indentation standards
where this is okay (e.g. Lisp); but for the most part, no.
Triggering re-indentation is trivial enough (=C-M-\=); I don't want it to
happen every time I start a new line.
#+BEGIN_SRC emacs-lisp
(set 'electric-indent-chars
(remq ?\n electric-indent-chars))
#+END_SRC
Indentation, by default, by my preference, should never insert tabs.
#+BEGIN_SRC emacs-lisp
(setq-default indent-tabs-mode nil)
#+END_SRC
*TODO:* But some projects I work on (such as GNU screen) do use tabs; write
a hook that will detect this and properly set =indent-tabs-mode=.
Indentation should also be done automatically when hitting =RET=, kind of
like Vim's =autoindent=:
#+BEGIN_SRC emacs-lisp
(define-key global-map
(kbd "RET") 'newline-and-indent)
#+END_SRC
**** Indentation Depth
Certain modes provide their own indentation settings, and my indentation
preferences vary depending on language. This list is incomplete.
#+BEGIN_SRC emacs-lisp
(setq sh-indentation 2
sh-basic-offset 2)
#+END_SRC
** Searching
Proper searching of text is an art---and I don't mean from a parsing
standpoint. Knowing how to navigate and mark portions of a text can be a
powerful productivity boost.
Hi Lock mode is one of those simple things that can really have a great
impact when you're trying to grok something with a number of pieces. It is
also great during presentations or peer programming/review:
#+BEGIN_SRC emacs-lisp
(global-hi-lock-mode t)
#+END_SRC
** Sentences
It is beneficial to be able to recognize, at a glance, the length of a
complete sentence; it helps to understand the scope of an idea or set of
ideas.
#+BEGIN_SRC emacs-lisp
(require 'sentence-highlight)
#+END_SRC
** Org Mode
#+INCLUDE: conf/org.org
* Mail
#+INCLUDE: conf/mail.org
* Web Browsing
There's more to be said on this topic; consider this section a TODO. I do
most things from the command line, so w3m is a suitable default.
#+BEGIN_SRC emacs-lisp
(require 'w3m)
(setq browse-url-browser-function
'w3m-browse-url)
#+END_SRC
With that said, there are situations where I may wish to toggle between w3m
and my default browser (w3m obviously does not support certain modern web
browser features).
#+BEGIN_SRC emacs-lisp
(define-key global-map
(kbd "\C-C \C-X \C-W")
(lambda ()
(interactive)
(setq browse-url-browser-function
(if (eq browse-url-browser-function 'browse-url-default-browser)
'w3m-browse-url
'browse-url-default-browser))
(message (symbol-name browse-url-browser-function))))
#+END_SRC
* Security and Cryptography
** GnuPG
Emacs' GnuPG (GPG) interface is <<<EasyPG>>>.
*** GPG Pinentry
The GPG pinentry dialog is a neat console-based dialog that consumes the TTY
and prompts for a password. In general, this works well; with Emacs, I
noticed that it fights for input.
To avoid the problem, I disable pinentry indirectly by clearing out the
=GPG_AGENT_INFO= environment variable.
#+BEGIN_SRC emacs-lisp
(defadvice epg--start (around advice-epg-disable-agent activate)
(setenv "GPG_AGENT_INFO" nil)
ad-do-it)
#+END_SRC

136
emacs.d/org.org 100644
View File

@ -0,0 +1,136 @@
#+TITLE: Mike Gerwitz's Emacs Org Mode Configuration
#+AUTHOR: Mike Gerwitz
#+EMAIL: mtg@gnu.org
[[http://orgmode.org][<<<Org mode>>>]] is an incredibly flexible system for note taking, task
management, authoring, content generation, literate programming, and
countless other things. It is amazing, and if you use it, so are
you. Many have began using Emacs purely to use Org; it was one of my
considerations, since there is no equivalent for Vim (or any other
editor, for that matter). This configuration file (and the output
that you may be reading) is written in and generated by Org.
If you do not know what Org mode is, then you should start researching
it immediately.
#+BEGIN_SRC emacs-lisp
(setq org-directory "~/org")
#+END_SRC
* Outline Display
Some of the options herein are default, but it helps to clarify them
for rationale, certainty, and ensuring that future changes in defaults
doesn't eff with my shit.
** Folding
Org, by default, collapses the outline (into an "overview") upon
entering =org-mode=. This is a convenient view for large outlines,
but is not something I particularly enjoy; I'll handle my own
collapsing if need be; I find it useful to see the whole document
immediately.
It is also an incredibly confusing option for beginners that have no
idea what is going on, or how to expand the outline. Not that I know
that from personal experience or anything. (Evil mode's keybinding
overrides didn't help that learning process any, either; I did
contribute a patch for vim-style folding that was accepted, though, so
that's solved.)
#+BEGIN_SRC emacs-lisp
(setq org-startup-folded nil)
#+END_SRC
The =foldout= package performs folding via buffer narrowing, which can be
convenient to relieve mental stress for larger documents.
#+BEGIN_SRC emacs-lisp
(eval-after-load "outline" '(require 'foldout))
#+END_SRC
** Indentation
Org's outline format is great, but it can be a bit obnoxious to
determine nesting at an arbitrary point: you have to visually
backtrack to the nearest heading to see its depth.
The easy solution is =org-indent-mode=, which indents text according
to the outline structure.
#+BEGIN_SRC emacs-lisp
(setq org-startup-indented t)
#+END_SRC
** Line Truncation
Line length is a constant debate, and is one that I (naturally) have
strong opinions on. Specifically, long lines (what I consider to be
"long") are a plague. =org-startup-truncated= can set
=truncate-lines= for you such that one line only gets one visual line
on the screen. That is a terrible idea! I do not want to scroll
horizontally to read someone else's terribly formatted text.
There may be some acceptable reasons for long line length, like long
URIs, or (very rarely) lines in programming languages that are not
easily broken due to syntatic peculiarities.
#+BEGIN_SRC emacs-lisp
(setq org-startup-truncated nil)
#+END_SRC
* Task Management
Org is an excellent tool for task management. Not only does it offer
varying degrees of flexibility with highly configurable options
(without having to write elisp), but it also has flexible constraint,
workflow, and reporting capabilities.
** Dependencies
It is useful to provide dependency constraints in TODO lists for both
data integrity and, well, sense. Org offers a couple different
options for this out of the box.[fn:: There is also [[http://orgmode.org/worg/org-contrib/org-depend.html][=org-depend=]],
a contributed module, that provides even greated flexibility. I have
not yet explored it, so I cannot provide any input as to its utility.]
#+BEGIN_SRC emacs-lisp
(setq org-enforce-todo-dependencies t
org-enforce-todo-checkbox-dependencies t)
#+END_SRC
To help make apparent those items that cannot be completed due to
dependency constraints, they can be visually dimmed in agenda views:
#+BEGIN_SRC emacs-lisp
(setq org-agenda-dim-blocked-tasks t)
#+END_SRC
** Capture
Org's "capture" feature (=org-capture=) allows for the quick capture
of notes (aha!) with little workflow interruption. I do not make as
much use of it as I should; I constantly have thoughts that result in
TODOs or other notes.
Org recommends a keybinding to invoke =org-capture=:
#+BEGIN_SRC emacs-lisp
(define-key global-map
"\C-cc" 'org-capture)
#+END_SRC
I call my default notes file my scratchpad; if things stay there too
long without being organized, then that's generally a bad thing, or
they're not all that important.
#+BEGIN_SRC emacs-lisp
(setq org-default-notes-file
(concat org-directory "/scratch.org"))
#+END_SRC
I need to create some templates; they'll be here when I do.
* Source Code
#+BEGIN_SRC emacs-lisp
(setq org-src-fontify-natively t)
#+END_SRC
#+BEGIN_SRC emacs-lisp
(push '("el" "#+BEGIN_SRC emacs-lisp\n?\n#+END_SRC"
"<src lang=\"emacs-lisp\">\n?\n</src>")
org-structure-template-alist)
#+END_SRC