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
parent
786c1099ff
commit
9ec0bea609
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue