From 9ec0bea60990141ba1ffab1879511c3a89466e9a Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Tue, 7 Jul 2015 23:07:23 -0400 Subject: [PATCH] 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. --- emacs.d/emacs.org | 920 ++++++++++++++++++++++++++++++++++++++++++++++ emacs.d/org.org | 136 +++++++ 2 files changed, 1056 insertions(+) create mode 100644 emacs.d/emacs.org create mode 100644 emacs.d/org.org diff --git a/emacs.d/emacs.org b/emacs.d/emacs.org new file mode 100644 index 0000000..df63bf5 --- /dev/null +++ b/emacs.d/emacs.org @@ -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 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= (==) 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 = and =C =. + +#+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 + +*** <<>> +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 +<<>> +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 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 <<>> for line numbering, but found that +it was far too slow due to my large terminal resolution. So, I gave +<<>> 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 +<<>> 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 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 <<>>. + +#+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 +<> +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 <<>> +<<>> +** 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 +<<>> +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. + +** <<>> (<<>>) +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 <<>>. + +*** 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 diff --git a/emacs.d/org.org b/emacs.d/org.org new file mode 100644 index 0000000..7b8f386 --- /dev/null +++ b/emacs.d/org.org @@ -0,0 +1,136 @@ +#+TITLE: Mike Gerwitz's Emacs Org Mode Configuration +#+AUTHOR: Mike Gerwitz +#+EMAIL: mtg@gnu.org + +[[http://orgmode.org][<<>>]] 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" + "\n?\n") + org-structure-template-alist) +#+END_SRC