927 lines
33 KiB
Org Mode
927 lines
33 KiB
Org Mode
#+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 for 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. Line numbers also help to
|
|
provide context when navigating large files.
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(evil-define-key 'normal global-map
|
|
"\C-n" 'nlinum-mode)
|
|
#+END_SRC
|
|
|
|
|
|
** 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
|