#+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. 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) (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 for 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. 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 <<>> 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" (interactive "nTab width: ") (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 (defun global-set-tab-width (width) "Set tab width to WIDTH and generate tab stops" (interactive "nTab width: ") (setq-default tab-width width) (setq-default tab-stop-list (number-sequence width 120 width))) (global-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