Skip to content

Latest commit

 

History

History
2083 lines (1583 loc) · 68.7 KB

emacs.org

File metadata and controls

2083 lines (1583 loc) · 68.7 KB

Emacs Configuration File

Introduction

This is my .emacs file, written using org-mode, so that I can organize it and take notes on all the complexity.

Emacs Executable

This file is really a script that requires version 24 of Emacs. While I often use Emacs for Mac, lately, I’ve been building from Homebrew with the following dependency:

brew cask install xquartz

And then built from source especially for the Mac:

brew install emacs --HEAD --use-git-head --with-cocoa \
      --with-gnutls --srgb --with-librsvg --with-ns

brew linkapps emacs

Not only does this install the latest version of Emacs in /usr/local/bin/emacs, but it also links a GUI version in /Application/Emacs.app.

All Homebrew options for Emacs can be seen with the command:

brew options emacs

Loading this File

To “load” the contents of this file, add the following to $HOME/.emacs:

;; Load our Literate Programming version of our Dot Emacs
;; file, from file: ~/Work/dot-files/emacs.org
(unless (boundp 'aquamacs-version)
 (load-file "~/.emacs.d/elisp/init-main.el")

 (when (window-system)
   (require 'init-client))

 (server-start))

Note: I only load this from a “normal” Emacs distribution, which allows me to play around with Aquamacs and Starter Kits for recommendations to people new to Emacs.

General Settings

My Directory Location

Normally, the user-emacs-directory stores everything in a .emacs.d directory in the home directory, however, Aquamacs overrides that, and since I now feel the need to use these settings for both editors (sure feels like XEmacs all over again).

Any way, I have a new global variable for that:

(defconst ha/emacs-directory (concat (getenv "HOME") "/.emacs.d/"))

(defun ha/emacs-subdirectory (d) (expand-file-name d ha/emacs-directory))

Directory Structure

In case this is the first time running this on a computer, we need to make sure the following directories have been created.

(let* ((subdirs '("elisp" "backups" "snippets" "ac-dict"))
       (fulldirs (mapcar (lambda (d) (ha/emacs-subdirectory d)) subdirs)))
  (dolist (dir fulldirs)
    (when (not (file-exists-p dir))
      (message "Make directory: %s" dir)
      (make-directory dir))))

Customization Section

While I would rather program my configurations, sometimes the Emacs menu system is “good enough”, but I want it in its own file:

(setq custom-file (expand-file-name "custom.el" ha/emacs-directory))
(when (file-exists-p custom-file)
  (load custom-file))

Setting up the Load Path

Extra packages not available via the package manager go in my personal stash at: $HOME/.emacs.d/elisp

(add-to-list 'load-path (ha/emacs-subdirectory "elisp"))

Load up my special collection of enhancements to Emacs Lisp:

(require 'init-support)
(require 'cl)

Package Initialization

Package Manager

Emacs has become like every other operating system, and now has a package manager with its own collection repository, but since it is so conservative, we need to add more repositories to get all the sweet goodness, I demand.

(require 'package)

(setq package-archives '(("org"       . "http://orgmode.org/elpa/")
                         ("gnu"       . "http://elpa.gnu.org/packages/")
                         ("melpa"     . "http://melpa.milkbox.net/packages/")
                         ("marmalade" . "http://marmalade-repo.org/packages/")))

While we can now do a package-list-packages, you can install and everything is good, however, we can’t require any of these packages (in order to customize them in this file) until we do this:

(package-initialize)
(package-refresh-contents)

Not sure why the package management system doesn’t come with a programmatic way to specify what packages should be installed. Oh yeah, this is pretty new. Looks like everyone just rolls there own, so this is mine.

(defun packages-install (packages)
  "Given a list of packages, this will install them from the standard locations."
  (let ((to-install (inverse-filter 'package-installed-p packages)))
    (when to-install
      (package-refresh-contents)
      (dolist (it to-install)
          (package-install it)
      (delete-other-windows)))))

Installing Extra Packages

This means that at any point in my configuration file, I can specify a list of packages to make sure they are installed.

(packages-install
               '(ace-jump-mode
                 ag
                 avy
                 company
                 company-quickhelp
                 company-math
                 dired-details
                 color-identifiers-mode  ;; Color variables differently
                 ctags-update
                 epl
                 esh-buf-stack
                 expand-region
                 flx
                 flx-ido
                 flycheck
                 flycheck-color-mode-line
                 git-blame
                 git-gutter-fringe
                 gitconfig-mode
                 gitignore-mode
                 graphviz-dot-mode
                 hungry-delete
                 htmlize
                 hydra
                 ido-vertical-mode
                 iy-go-to-char
                 linum-relative
                 magit
                 markdown-mode
                 multiple-cursors
                 paredit
                 redo+             ;; If not installed, edit mac-key-mode
                 smex
                 thesaurus
                 undo-tree
                 visual-regexp
                 yasnippet))

Use-Package

Just beginning to use use-package. I’m sure it will be a long time to finally convert everything.

(require 'use-package)

Variables

General settings about me that other packages can use. The biggest problem is guessing my email address based on what computer I am using:

(if (equal "howard.abrams" user-login-name)
    (setq user-mail-address "howard.abrams@workday.com")
  (setq user-mail-address "howard.abrams@gmail.com"))

Tabs vs Spaces

I have learned to distrust tabs in my source code, so let’s make sure that we only have spaces. See this discussion for details.

(setq-default indent-tabs-mode nil)
(setq tab-width 2)

Make tab key do indent first then completion.

(setq-default tab-always-indent 'complete)

Aggressive Auto Indention

Automatically indent without use of the tab found in this article, and seems to be quite helpful for many types of programming languages.

To begin, we create a function that can indent a function by calling indent-region on the beginning and ending points of a function.

(defun indent-defun ()
  "Indent current defun.
Do nothing if mark is active (to avoid deactivaing it), or if
buffer is not modified (to avoid creating accidental
modifications)."
  (interactive)
  (unless (or (region-active-p)
              buffer-read-only
              (null (buffer-modified-p)))
    (let ((l (save-excursion (beginning-of-defun 1) (point)))
          (r (save-excursion (end-of-defun 1) (point))))
      (cl-letf (((symbol-function 'message) #'ignore))
        (indent-region l r)))))

Next, create a hook that will call the indent-defun with every command call:

(defun activate-aggressive-indent ()
  "Locally add `ha/indent-defun' to `post-command-hook'."
  (add-hook 'post-command-hook
            'indent-defun nil 'local))

The trick is to add the following to each programming hook:

(add-hook 'emacs-lisp-mode-hook 'activate-aggressive-indent)

Encrypting Files

Synchronize notes formatted in org-mode across multiple computers with cloud storage services, like Dropbox? Those files are cached in various other storage facilities… so, I use symmetric key encryption with PGP.

To get started on the Mac, install the goodies:

brew install gpg

Now, any file loaded with a gpg extension, e.g. some.org.gpg, will prompt for a password (and then use org-mode). Since these files are for my eyes only, I don’t need the key-ring prompt:

(setq epa-file-select-keys 2)

If you trust your Emacs session on your computer, you can have Emacs cache the password. Not sure I do…

(setq epa-file-cache-passphrase-for-symmetric-encryption t)

Display Settings

I’ve been using Emacs for many years, and appreciate a certain minimalist approach to its display. While you can turn these off with the menu items now, it is just as easy to set them here.

(setq initial-scratch-message "") ;; Uh, I know what Scratch is for
(setq visible-bell t)             ;; Get rid of the beeps

(when (window-system)
  (tool-bar-mode 0)               ;; Toolbars were only cool with XEmacs
  (when (fboundp 'horizontal-scroll-bar-mode)
    (horizontal-scroll-bar-mode -1))
  (scroll-bar-mode -1))            ;; Scrollbars are waste screen estate

Most of the display settings actually come from the Mac initialization file.

Mode Line

My mode-line code is now more complex in order to make it more simpler.

(require 'init-mode-line)

Key Bindings

Function Key Definitions

Clearly, the most important keybindings are the function keys, right? Here is my list of needs:

  • F1 - Help? Isn’t Control-H good enough?
  • F2 - Standard alternate meta key with lots of bindings
  • F3 - Define a keyboard macro
  • F4 - Replay a keyboard macro
  • F5 - Use org-mode’s Mark Ring feature globally
  • F6 - Open to temporary, changeable commands…
  • F7 - Switch to another window … Shift goes the other way.
  • F8 - Switch to buffer
  • F9 - My other meta key for changing colors and other odd bindings that I actually don’t use that often
(global-set-key (kbd "<f5>") 'org-mark-ring-push)
(global-set-key (kbd "C-<f5>") 'org-mark-ring-goto)
;; (global-set-key (kbd "<f6>") ')
(global-set-key (kbd "<f7>") 'other-window)
(global-set-key (kbd "<f8>") 'ido-switch-buffer)

Set up ace-window mode:

(when (require 'ace-window nil t)
      (global-set-key (kbd "<f7>") 'ace-window)
      (global-set-key (kbd "C-<f7>") (lambda () (interactive) (ace-window 4)))
      (global-set-key (kbd "M-<f7>") (lambda () (interactive) (ace-window 8))))

At some point, I will want to choose window labels based on the right hand (since F7) is on the left side of my keyboards.

(setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))

I like kpm-list a bit better than ibuffer, but I really don’t use either more than ido-switch-buffer. Still:

(if (require 'kpm-list nil t)
    (global-set-key (kbd "S-<f8>") 'kpm-list)
  (global-set-key (kbd "S-<f8>") 'ibuffer))

F2 and F9 Helpers

The F9 prefix is scattered about my config files.

(define-prefix-command 'personal-global-map)
(global-set-key (kbd "<f9>") 'personal-global-map)

(define-key personal-global-map (kbd "b") 'bury-buffer)

Unlike the F9 bindings, all the F2 key-bindings happen in a single library file:

(require 'init-f2)

Auto Hiding Functions

Big, structured file, like source code, hide all of the functions, and selectively reveal them, using hide-show-mode. I don’t like the complicated key-bindings, so I through them on the <f9>:

(defun ha-hs-hide-all ()
  "Wrapper around 'hs-hide-all' that turns on the minor mode."
  (interactive)
  (hs-minor-mode t)
  (hs-hide-all))

(define-key personal-global-map (kbd "M-H") 'ha-hs-hide-all)
(define-key personal-global-map (kbd "H") 'hs-hide-block)
(define-key personal-global-map (kbd "M-V") 'hs-show-all)
(define-key personal-global-map (kbd "V") 'hs-show-block)

While ‘S’ does make sense for showing, I’m already using that for ‘Stop’. Besides, ‘viewing’ isn’t a bad mnemonic.

Easy Highlighting

I like the ability to highlight random text.

(define-key personal-global-map (kbd "h") 'highlight-regexp)
(define-key personal-global-map (kbd "u") 'unhighlight-regexp)

May get specific highlights automatically for certain files. We begin by highlighting lines in *.log files.

(defun highlite-it ()
  "Highlight certain lines in specific files. Currently, only log files are supported."
  (interactive)
  (when (equal "log" (file-name-extension (buffer-file-name)))
        (hi-lock-mode 1)
        (highlight-lines-matching-regexp "ERROR:" 'hi-red-b)
        (highlight-lines-matching-regexp "NOTE:" 'hi-blue-b)))

(add-hook 'find-file-hook 'highlite-it)

Turn on specific word groupings for specific occasions. We begin with highlighting keywords I use during note-taking sessions at the end of a sprint.

(defun ha/sprint-retrospective-highlighting ()
  "Highlights the good, the bad and the improvements to make when taking notes."
  (interactive)
  (hi-lock-mode t)
  (highlight-lines-matching-regexp "^   [-*] " 'hi-black-b)
  (highlight-phrase "TODO:?" 'hi-black-b)
  (highlight-regexp "(?Good)?:?" 'hi-green-b)
  (highlight-regexp "(?Bad)?:?" 'hi-red-b)
  (highlight-regexp "Imp\\(rove\\)?:" 'hi-blue-b))

Controlling Windows

Often, while on my laptop, I want the current window to be ‘large enough for work’, and this is bound to <f9> . (period).

(define-key personal-global-map (kbd ",") 'ha/window-standard-size)

If I’ve enlarged the window, I can restore that window to its original size, so this requires a buffer local variable:

(make-variable-buffer-local 'window-width-original)

Now a function that either changes the width to 80, or back to the original size if already at 80.

(defun ha/window-standard-size (arg)
  "Sets the size of the current window to 80 characters, unless
it already is 80 characters, in which case, set it back to its
previous size. A prefix ARG can be given to set the window to a
particular width."
  (interactive "p")

  ;; If not already set, let's store the current window width in our
  ;; buffer-local variable.
  (if (not (local-variable-p 'window-width-original))
      (setq window-width-original (window-width)))

  ;; The 'goal' is 80 unless we get a better argument, C-u 60 ...
  (let* ((goal-width (if (> arg 8) arg 80))
         (new-width (- goal-width (window-width))))

    (if (= new-width 0)    ; Already enlarged? Restore:
        (enlarge-window-horizontally (- window-width-original goal-width))
      (enlarge-window-horizontally new-width))))

Other Key Bindings

After picking up an Advantage Kinesis, I decided that I wanted to redo some of the bindings to make it easier on me…mainly because the Shift key is now really, really hard to reach.

(global-set-key (kbd "M-<left>") 'beginning-of-line)
(global-set-key (kbd "M-<right>") 'end-of-line)
(global-set-key (kbd "C-M-<left>") 'beginning-of-buffer)
(global-set-key (kbd "C-M-<right>") 'end-of-buffer)

Why isn’t imenu bound?

(global-set-key (kbd "M-s f") 'imenu)
(global-set-key (kbd "M-s M-f") 'imenu)

Better jumping around the buffer with ace-jump-mode and friends.

(when (require 'ace-jump-mode nil t)
  (global-set-key (kbd "C-c SPC") 'ace-jump-mode)
  (global-set-key (kbd "C-c C-SPC") 'ace-jump-mode-pop-mark)

  (global-set-key (kbd "M-s s") 'ace-jump-mode)   ;; Needed for org-mode files
  (global-set-key (kbd "M-s a") 'avi-goto-char)
  (global-set-key (kbd "M-s w") 'avi-goto-word-1)
  (global-set-key (kbd "M-s l") 'avi-goto-line))
  • C-c SPCace-jump-word-mode enter first character of a word, select the highlighted key to move to it.
  • C-u C-c SPCace-jump-char-mode enter a character for query, select the highlighted key to move to it.
  • C-u C-u C-c SPCace-jump-line-mode each non-empty line will be marked, select the highlighted key to move to it.
  • M-s lavi-goto-line … works well with org-mode files.
  • M-s .isearch-forward-symbol-at-point search forward to whatever is at point, but you need to C-s to jump to next match.
  • M-s _isearch-forward-symbol

Using avy as an extension to the normal isearch, so that if I type a search phrase, I can then type C-' to kick off avy-isearch, and jump to the one that I want. Little change to the mental flow.

(when (require 'avy nil t)
 (define-key isearch-mode-map (kbd "C-'") 'avy-isearch))

Unfill Paragraph

Unfilling a paragraph joins all the lines in a paragraph into a single line. Taken from here.

(defun unfill-paragraph ()
  "Takes a multi-line paragraph and makes it into a single line of text."
  (interactive)
  (let ((fill-column (point-max)))
    (fill-paragraph nil)))

;; Handy key definition
(define-key global-map "\M-Q" 'unfill-paragraph)

General Behavior Fixes

The subtle changes I’ve been making to Emacs behavior has grown until I felt I should move it into its own source file.

(require 'init-fixes)

Multiple Cursors

While I’m not sure how often I will use multiple-cursors project, I’m going to try to remember it is there. It doesn’t have any default keybindings, so I set up the suggested:

(when (require 'multiple-cursors nil t)
      (global-set-key (kbd "C->") 'mc/mark-next-like-this)
      (global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
      (global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this))

Expand Region

Wherever you are in a file, and whatever the type of file, you can slowly increase a region selection by logical segments.

(require 'expand-region)
(global-set-key (kbd "C-=") 'er/expand-region)

This works really well with other commands, including fancy-narrow, where I can visually high-light a section of a buffer. Great for code-reviews and other presentations.

(when (require 'fancy-narrow nil t)
  (defun ha/highlight-block ()
    "Highlights a 'block' in a buffer defined by the first blank
     line before and after the current cursor position. Uses the
     'fancy-narrow' mode to high-light the block."
    (interactive)
    (let (cur beg end)
      (setq cur (point))
      (setq end (or (re-search-forward  "^\s*$" nil t) (point-max)))
      (goto-char cur)
      (setq beg (or (re-search-backward "^\s*$" nil t) (point-min)))
      (fancy-narrow-to-region beg end)
      (goto-char cur)))

  (defun ha/highlight-section (num)
    "If some of the buffer is highlighted with the 'fancy-narrow'
     mode, then un-highlight it by calling 'fancy-widen'.

     If region is active, call 'fancy-narrow-to-region'.

     If given a prefix value, C-u, highlight the current
     block (delimited by blank lines). Otherwise, called
     'fancy-narrow-to-defun, to highlight current function."
    (interactive "p")
    (cond
     ((fancy-narrow-active-p) (fancy-widen))
     ((> num 1)               (ha-highlight-block))
     ((region-active-p)       (fancy-narrow-to-region (region-beginning) (region-end)))
     ;; Want to do something special in org-mode? Probably...
     ;; ((derived-mode-p 'org-mode) ...)
     (t                       (fancy-narrow-to-defun))))

  (global-set-key (kbd "C-M-+") 'ha/highlight-section))

Block Wrappers

The M-( binding to insert-pair is great, but we often need to wrap other commands. Thankfully, insert-pair is up to the task by simply having new bindings.

(global-set-key (kbd "M-[") 'insert-pair)
(global-set-key (kbd "M-{") 'insert-pair)
(global-set-key (kbd "M-<") 'insert-pair)
(global-set-key (kbd "M-'") 'insert-pair)
(global-set-key (kbd "M-`") 'insert-pair)
(global-set-key (kbd "M-\"") 'insert-pair)

But in order to wrap text in a more general way (with just about any textual string), we need something more. Especially with the expand-region command, wrapping a logical block of text with a beginning and ending string really makes sense.

(defun surround (start end txt)
 "Wraps the specified region (or the current 'symbol / word'
with some textual markers that this function requests from the
user. Opening-type text, like parens and angle-brackets will
insert the matching closing symbol.

This function also supports some org-mode wrappers:

  - `#s` wraps the region in a source code block
  - `#e` wraps it in an example block
  - `#q` wraps it in an quote block"
  (interactive "r\nsEnter text to surround: " start end txt)

  ;; If the region is not active, we use the 'thing-at-point' function
  ;; to get a "symbol" (often a variable or a single word in text),
  ;; and use that as our region.

  (if (not (region-active-p))
      (let ((new-region (bounds-of-thing-at-point 'symbol)))
        (setq start (car new-region))
        (setq end (cdr new-region))))

    ;; We create a table of "odd balls" where the front and the end are
    ;; not the same string.
  (let* ((s-table '(("#e" . ("#+BEGIN_EXAMPLE\n" "\n#+END_EXAMPLE") )
  ("#s" . ("#+BEGIN_SRC \n"    "\n#+END_SRC") )
  ("#q" . ("#+BEGIN_QUOTE\n"   "\n#+END_QUOTE"))
  ("<"  . ("<" ">"))
  ("("  . ("(" ")"))
  ("{"  . ("{" "}"))
  ("["  . ("[" "]"))))    ; Why yes, we'll add more
  (s-pair (assoc-default txt s-table)))

  ;; If txt doesn't match a table entry, then the pair will just be
  ;; the text for both the front and the back...
  (unless s-pair
  (setq s-pair (list txt txt)))

  (save-excursion
  (narrow-to-region start end)
  (goto-char (point-min))
  (insert (car s-pair))
  (goto-char (point-max))
  (insert (cadr s-pair))
  (widen))))

  (global-set-key (kbd "C-+") 'surround)

To make it easier to call from other functions, let’s wrap that wrapper:

(defun surround-text (txt)
  (if (region-active-p)
      (surround (region-beginning) (region-end) txt)
    (surround nil nil txt)))

Kill Entire Lines

While C-k kills text to the end of the line, what about killing text before the point?

(defun ha/kill-line-before ()
  "Kills text from the current cursor position to the beginning
of the current line."
  (interactive)
  (kill-region (point-at-bol) (point)))

(global-set-key (kbd "C-S-K") 'ha/kill-line-before)

According to this article, killing the rest of the line is fine, but C-3 C-k kills only 2½ lines. Not so useful.

This creates a macro that moves to the beginning of the line and then calls a function given to it. Quite an interesting approach:

(defmacro bol-with-prefix (function)
  "Define a new function which calls FUNCTION.
Except it moves to beginning of line before calling FUNCTION when
called with a prefix argument. The FUNCTION still receives the
prefix argument."
  (let ((name (intern (format "ha/%s-BOL" function))))
    `(progn
       (defun ,name (p)
         ,(format
           "Call `%s', but move to the beginning of the line when called with a prefix argument."
           function)
         (interactive "P")
         (when p
           (forward-line 0))
         (call-interactively ',function))
       ',name)))

And we re-bind them to functions that use them.

(global-set-key [remap paredit-kill] (bol-with-prefix paredit-kill))
(global-set-key [remap org-kill-line] (bol-with-prefix org-kill-line))
(global-set-key [remap kill-line] (bol-with-prefix kill-line))

(global-set-key (kbd "C-k") (bol-with-prefix kill-line))

Hydra Sequences

I’m starting to appreciate the Hydra project.

(require 'hydra)

(defhydra hydra-zoom (global-map "<f9>")
  "zoom"
  ("+" text-scale-increase "in")
  ("=" text-scale-increase "in")
  ("-" text-scale-decrease "out"))

Change window configuration and then return to the old configuration with winner-mode. Use Control-C Arrow keys to cycle through window/frame configurations.

(winner-mode 1)

(defhydra hydra-winner (global-map "<f9> c")
  "zoom"
  ("<left>" winner-undo "undo-window")
  ("<right>" winner-redo "redo-window"))

Easily manipulate the size of the windows using the arrow keys in a particular buffer window.

(require 'windmove)

(defun hydra-move-splitter-left (arg)
  "Move window splitter left."
  (interactive "p")
  (if (let ((windmove-wrap-around))
        (windmove-find-other-window 'right))
      (shrink-window-horizontally arg)
    (enlarge-window-horizontally arg)))

(defun hydra-move-splitter-right (arg)
  "Move window splitter right."
  (interactive "p")
  (if (let ((windmove-wrap-around))
        (windmove-find-other-window 'right))
      (enlarge-window-horizontally arg)
    (shrink-window-horizontally arg)))

(defun hydra-move-splitter-up (arg)
  "Move window splitter up."
  (interactive "p")
  (if (let ((windmove-wrap-around))
        (windmove-find-other-window 'up))
      (enlarge-window arg)
    (shrink-window arg)))

(defun hydra-move-splitter-down (arg)
  "Move window splitter down."
  (interactive "p")
  (if (let ((windmove-wrap-around))
        (windmove-find-other-window 'up))
      (shrink-window arg)
    (enlarge-window arg)))

(defhydra hydra-splitter (global-map "<f9>")
  "splitter"
  ("<left>" hydra-move-splitter-left)
  ("<down>" hydra-move-splitter-down)
  ("<up>" hydra-move-splitter-up)
  ("<right>" hydra-move-splitter-right))

Loading and Finding Files

Projectile

The Projectile project is a nifty way to run commands and search for files in a particular “project”. Its necessity is less now that IDO with flexible matching seems to always just find what I need.

Still…

(when (require 'projectile nil t)
  (require 'projectile)
  (projectile-global-mode))

Dired Options

The associated group name isn’t too useful when viewing the dired output.

(setq ls-lisp-use-insert-directory-program nil)

This enhancement to dired hides the ugly details until you hit ‘(’ and shows the details with ‘)’. I also change the […] to a simple asterisk.

(when (require 'dired-details nil t)
  (dired-details-install)
  (setq dired-details-hidden-string "* "))

The ability to create a dired buffer based on searching for files in a directory tree with find-name-dired is fantastic. The following magic optimizes this approach:

(require 'find-dired)
(setq find-ls-option '("-print0 | xargs -0 ls -od" . "-od"))

The dired-x project seems useful:

(add-hook 'dired-load-hook
          (lambda ()
            (load "dired-x")))

Tramp

The ability to edit files on remote systems is a wonderful win, since it means I don’t need to have my Emacs environment running on remote machines (still a possibility, just not a requirement).

According to the manual, I can access a file over SSH, via:

/ssh:10.52.224.67:blah

If I set the default method to SSH, I can do this:

/10.52.224.67:blah

So, let’s do it…

(setq tramp-default-method "ssh")

Come back someday, and see if the vagrant-tramp project starts working, as that would be nice to access files like:

/vagrant:collectd-server:/var/chef/cache/chef-stacktrace.out

Editing Root Files

According to Emacs Fu, we can use the wonderful Tramp to edit Root-owned files, as in:

(defun ha/find-file-as-root ()
  "Like `ido-find-file, but automatically edit the file with
root-privileges (using tramp/sudo), if the file is not writable by
user."
  (interactive)
  (let ((file (ido-read-file-name "Edit as root: ")))
    (unless (file-writable-p file)
      (setq file (concat "/sudo:root@localhost:" file)))
    (find-file file)))

The trick, as always, is finding the correct keybinding… but I have the C-c f as prefix for loading all sorts of files…

(global-set-key (kbd "C-c f r") 'ha/find-file-as-root)

IDO (Interactively DO Things)

According to Mickey, IDO is the greatest thing.

(setq ido-enable-flex-matching t)
(setq ido-everywhere t)
(flx-ido-mode 1)

According to Ryan Kneufeld, we could make IDO work vertically, which is much easier to read. For this, I use ido-vertically:

(require 'ido-vertical-mode)
(ido-mode 1)
(ido-vertical-mode 1)

; I like up and down arrow keys:
(setq ido-vertical-define-keys 'C-n-C-p-up-and-down)

SMEX

Built using IDO.

(require 'smex)
(smex-initialize) ; Can be omitted. This might cause a (minimal) delay

(global-set-key (kbd "M-x") 'smex)
(global-set-key (kbd "M-z") 'smex)  ;; Zap to char isn't so helpful
(global-set-key (kbd "M-X") 'smex-major-mode-commands)

;; This is our old M-x.
(global-set-key (kbd "C-c C-c M-x") 'execute-extended-command)

Not crazy about zap-to-char being so close to the very useful M-x sequence, so…

(global-set-key (kbd "M-z") 'smex-major-mode-commands)

Grep for my Notes

I have a voluminous amount of org-mode text files I routinely need search and filter.

I use the standard grep package in Emacs, but need a later version of Gnu Grep. On Mac OS X, run these two commands:

brew tap homebrew/dupes
brew install homebrew/dupes/grep

Silver Searcher

With Wilfred Hughes fancy ag package, I’ve switch from ack to the Silver Searcher:

brew install ag

Best part about the ag package, is not needing any configuration (as all functions are load-on demand).

ag-project-at-point
sets the query with the word at point, use: C-c p s s
ag-regexp
searches for regular expressions in a chosen directory (Note: the ag command prompts with regexp, but it adds a --literal option to the command)
C-u
Adding a prefix adds command line options, like -s or -i to specify case-sensitivity.

Create collection of ignorable files so it doesn’t look in backup files:

#.*

Using the latest version of ag? Highlight the keywords:

(use-package ag
  :init      (setq ag-highlight-search t)
  :config    (add-to-list 'ag-arguments "--word-regexp"))

Personally, I’m almost always looking for full words:

Spotlight

However, I also need a global indexing approach to searching through my notes, and since I’m usually on a Mac, I might as well use the Spotlight service that is already running:

(setq locate-command "mdfind")  ;; Use Mac OS X's Spotlight
(global-set-key (kbd "C-c f l") 'locate)

The following function wraps locate-with-filter to only grab org-mode files:

(defun locate-org-files (search-string)
  (interactive "sSearch string: ")
  (locate-with-filter search-string ".org$"))

(global-set-key (kbd "C-c f o") 'locate-org-files)

We could limit the location that Spotlight request searches:

(defun locate-my-org-files (search-string)
  (let ((tech (concat (getenv "HOME") "/technical"))
        (pers (concat (getenv "HOME") "/personal"))
        (note (concat (getenv "HOME") "/notes"))
        (jrnl (concat (getenv "HOME") "/journal")))
    (-flatten (list "mdfind"
             (if (file-exists-p tech) (list "-onlyin" tech))
             (if (file-exists-p pers) (list "-onlyin" pers))
             (if (file-exists-p note) (list "-onlyin" note))
             (if (file-exists-p jrnl) (list "-onlyin" jrnl))
             "-interpret" search-string))))

(setq locate-make-command-line 'locate-my-org-files)

However, the problem with locate, is it doesn’t show me any context. My find-notes script uses both mdfind and grep to both better search and display some useful context.

Just need to wrap that in a function:

(defun find-notes (words)
  "Uses my 'find-notes' shell script as a better grep
utility. Not only does it show the results in a clickable list,
it also highlights the result, allowing us to put more context in
the output."
  (interactive "sSearch for words:")
  (let ((program (concat (getenv "HOME") "/bin/find-notes"))
        (buffer-name (concat "*find-notes: " words "*")))
    (call-process program nil buffer-name t words)
    (switch-to-buffer buffer-name)
    (read-only-mode 1)
    (grep-mode)
    (toggle-truncate-lines)
    (beginning-of-buffer)
    (dolist (word (split-string words))
      (highlight-regexp word))))

(global-set-key (kbd "C-x C-n") 'find-notes)

Recent File List

According to this article, Emacs already has the recent file listing available, just not turned on.

(require 'recentf)
(recentf-mode 1)
(setq recentf-max-menu-items 25)
(global-set-key (kbd "C-c f f") 'recentf-open-files)

Backup Settings

This setting moves all backup files to a central location. Got it from this page.

(setq backup-directory-alist
      `(("." . ,(expand-file-name
                 (ha/emacs-subdirectory "backups")))))

Make backups of files, even when they’re in version control

(setq vc-make-backup-files t)

And let’s make sure our files are saved if we wander off:

(defun save-all ()
  "Saves all dirty buffers without asking for confirmation."
  (interactive)
  (save-some-buffers t))

(add-hook 'focus-out-hook 'save-all)

Word Smithing

Auto Insertion

Just beginning to get a collection of templates to automatically insert if a blank file is loaded.

(add-hook 'find-file-hook 'auto-insert)
(auto-insert-mode 1)

(setq auto-insert-directory (ha/emacs-subdirectory "templates/"))
(setq auto-insert-query nil) ;;; If you don't want to be prompted before insertion

(define-auto-insert "\.el" "default-lisp.el")

Some auto insertion requires entering data for particular fields, and for that Yasnippet is better, so in this case, we combine them:

(defun ha/autoinsert-yas-expand()
  "Replace text in yasnippet template."
  (yas-expand-snippet (buffer-string) (point-min) (point-max)))

(define-auto-insert "\\.sh$" ["default-sh.sh" ha/autoinsert-yas-expand])
(define-auto-insert "/bin/"  ["default-sh.sh" ha/autoinsert-yas-expand])

Auto Complete

Using company-mode for all my auto completion needs.

(add-hook 'after-init-hook 'global-company-mode)

If the company-quickhelp is installed, let’s take advantage of it:

(company-quickhelp-mode 1)

This also requires pos-tip.

And I really like this idea of being able to easily insert math symbols based on LaTeX keywords:

(add-to-list 'company-backends 'company-math-symbols-unicode)

Yasnippets

The yasnippet project allows me to create snippets of code that can be brought into a file, based on the language.

(require 'yasnippet)
(yas-global-mode 1)

Helper function so that we can automatically expand a snippet programmatically, which makes it easier to do this with auto-insert:

(defun yas--expand-by-uuid (mode uuid)
  "Exapnd snippet template in MODE by its UUID"
  (yas-expand-snippet
   (yas--template-content
    (yas--get-template-by-uuid mode uuid))))

Inside the snippets directory should be directories for each mode, e.g. clojure-mode and org-mode. This connects the mode with the snippets.

(add-to-list 'yas-snippet-dirs (ha/emacs-subdirectory "snippets"))

js2-mode is good, but its name means that Yas’ won’t automatically link it to its js-mode. This little bit of magic does the linking:

(add-hook 'js2-mode-hook '(lambda ()
                            (make-local-variable 'yas-extra-modes)
                            (add-to-list 'yas-extra-modes 'js-mode)
                            (yas-minor-mode 1)))

Abbreviation Mode

Using the built-in Abbreviation Mode, and setting it up globally.

(setq-default abbrev-mode t)

Stop asking whether to save newly added abbrev when quitting Emacs.

(setq save-abbrevs nil)

While you can make abbreviations in situ, I figured I should pre-load a bunch that I use, but make a distinction between abbreviations that would be available globally, and in particular modes (especially the text modes, like org-mode):

(define-abbrev-table 'global-abbrev-table
    '(("8ha" "Howard Abrams")
      ("8fun" "function")
      ("8l" "lambda")))

This allows me to write 8ha as Howard Abrams.

(define-abbrev-table 'text-mode-abbrev-table
  '(("8js" "JavaScript")
    ("8cs" "CoffeeScript")
    ("8os" "OpenStack")
    ("8ng" "AngularJS")
    ("8wd" "Workday")
    ("btw" "by the way")
    ("note:" "*Note:*")))

Note: Capitalizing the first letter, i.e. Btw, expands the abbreviation with an initial capital, i.e. By the way … Sweet.

Spelling Correction with Abbreviation Mode

According to this discussion, we can correct a misspelled word with C-x C-i and it will use the abbreviation mode to automatically correct that word…as long as you misspell it the same way each time.

(define-key ctl-x-map "\C-i" 'endless/ispell-word-then-abbrev)

(defun endless/ispell-word-then-abbrev (p)
  "Call `ispell-word'. Then create an abbrev for the correction made.
With prefix P, create local abbrev. Otherwise it will be global."
  (interactive "P")
  (let ((bef (downcase (or (thing-at-point 'word) ""))) aft)
    (call-interactively 'ispell-word)
    (setq aft (downcase (or (thing-at-point 'word) "")))
    (unless (string= aft bef)
      (message "\"%s\" now expands to \"%s\" %sally"
               bef aft (if p "loc" "glob"))
      (define-abbrev
        (if p global-abbrev-table local-abbrev-table)
        bef aft))))

(setq save-abbrevs t)
(setq-default abbrev-mode t)

Spell Checking

I like spell checking with FlySpell, which uses the built-in spell-check settings of ispell.

Seems like I would want this automatically turned on for all text modes (but not for log files).

(dolist (hook '(text-mode-hook org-mode-hook))
  (add-hook hook (lambda () (flyspell-mode 1))))

(dolist (hook '(change-log-mode-hook log-edit-mode-hook org-agenda-mode-hook))
  (add-hook hook (lambda () (flyspell-mode -1))))

The downside of using single quotes, like ’ is that the ispell dictionary doesn’t recognize it as an apostrophe, so don’t is often looked at as incorrect.

(eval-after-load "ispell"
  '(add-to-list 'ispell-local-dictionary-alist '(nil
                                                "[[:alpha:]]"
                                                "[^[:alpha:]]"
                                                "['‘’]"
                                                t
                                                ("-d" "en_US")
                                                nil
                                                utf-8)))

Just not sure which of the three major spell checking systems to use. Currently, liking ASpell at this point.

ISpell

Setting this to the American dictionary seems to make it work better with Homebrew.

(setq ispell-dictionary "american")

ASpell automatically configures a personal dictionary at: ~/.aspell.en.pws, so no need to configure that.

ASpell

Seems that the ASpell is better supported than ISpell.

brew install aspell

And then configure it with the following:

(setq ispell-program-name "/usr/local/bin/aspell")
(setq ispell-extra-args '("--sug-mode=ultra" "--lang=en_US"))

To get Flyspell to work with Aspell, I need to do this:

(setq ispell-list-command "--list")

Online Thesaurus

Using thesaurus.el to access the Big Huge Labs’ Online Thesaurus while editing my expressive literary style in my text files.

(when (require 'thesaurus nil t)
  (thesaurus-set-bhl-api-key-from-file "~/.emacs.d/bighugelabs.apikey.txt")

  (define-key personal-global-map (kbd "t") 'thesaurus-choose-synonym-and-replace))

Miscellaneous Settings

Line Numbers

Turn linum-mode on/off with Command-K (see the Macintosh section above). However, I turn this on automatically for programming modes.

(add-hook 'prog-mode-hook 'linum-mode)

If we make the line numbers a fixed size, then increasing or decreasing the font size doesn’t truncate the numbers:

(defun fix-linum-size ()
  (interactive)
  (set-face-attribute 'linum nil :height 110))

(add-hook 'linum-mode-hook 'fix-linum-size)

If we alternate between line numbers and no-line numbers, I also have to turn on/off the fringe. Actually, this is really only useful when giving presentations.

(defun linum-off-mode ()
  "Toggles the line numbers as well as the fringe. This allows me
to maximize the screen estate."
  (interactive)
  (if linum-mode
      (progn
        (fringe-mode '(0 . 0))
        (linum-mode -1))
    (fringe-mode '(8 . 0))
    (linum-mode 1)))

  (global-set-key (kbd "A-C-K") 'linum-off-mode)
  (global-set-key (kbd "s-C-K") 'linum-off-mode)  ;; For Linux

I’m intrigued with the linum-relative mode (especially since I can toggle between them). The idea is that I can see the line that I want to jump to (like one 9 lines away), and then C-9 C-n to quickly pop to it.

(if (not (require 'linum-relative nil t))

    ;; If this isn't installed, we'll just toggle between showing and
    ;; not showing the line numbers.
    (progn
      (global-set-key (kbd "A-k") 'linum-mode)
      (global-set-key (kbd "s-k") 'linum-mode))   ;; For Linux

  ;; Otherwise, let's take advantage of the relative line numbering:
  (defun linum-new-mode ()
    "If line numbers aren't displayed, then display them.
     Otherwise, toggle between absolute and relative numbers."
    (interactive)
    (if linum-mode
        (linum-relative-toggle)
      (linum-mode 1)))

  (global-set-key (kbd "A-k") 'linum-new-mode)
  (global-set-key (kbd "s-k") 'linum-new-mode))   ;; For Linux

Smart Scan

Use the M-n to search the buffer for the word the cursor is currently pointing. M-p to go backwards.

(load-library "smart-scan")

Strip Whitespace on Save

When I save, I want to always, and I do mean always strip all trailing whitespace from the file.

(add-hook 'before-save-hook 'delete-trailing-whitespace)

Better Searching and Visual Regular Expressions

Only after you’ve started an isearch-forward do you wish you had regular expressions available, so why not just switch those defaults?

(global-set-key (kbd "C-s") 'isearch-forward-regexp)
(global-set-key (kbd "C-r") 'isearch-backward-regexp)
(global-set-key (kbd "C-M-s") 'isearch-forward)
(global-set-key (kbd "C-M-r") 'isearch-backward)

The Visual Regular Expressions project highlights the matches while you try to remember the differences between Perl’s regular expressions and Emacs’…

Begin with C-c r then type the regexp. To see the highlighted matches, type C-c a before you hit ‘Return’ to accept it.

(require 'visual-regexp)
(define-key global-map (kbd "C-c r") 'vr/replace)
(define-key global-map (kbd "C-c q") 'vr/query-replace)

;; if you use multiple-cursors, this is for you:
(define-key global-map (kbd "C-c m") 'vr/mc-mark)

Flycheck

Flycheck seems to be quite superior to good ol’ Flymake.

(when (require 'flycheck nil t)
  (add-hook 'after-init-hook #'global-flycheck-mode))

The most interesting aspect is that it doesn’t support Clojure.

Hungry Delete

With this free feature, deleting any space, deletes ALL spaces. Not sure if I like it, or not.

(require 'hungry-delete)
(global-hungry-delete-mode)

Programming Languages

All programming languages require some sort of tagging. but after thirty years, we are still using good ol’ ctags…well, Exuberant Ctags. Install with Homebrew:

brew install --HEAD ctags

On Ubuntu Linux, do:

sudo apt-get install -y exuberant-ctags

Note: for every project, run the following command:

ctags -e -R .

However, with the fancy new ctags-update package, this happens whenever we save a file:

(autoload 'turn-on-ctags-auto-update-mode
  "ctags-update" "turn on `ctags-auto-update-mode'." t)
(add-hook 'c-mode-common-hook  'turn-on-ctags-auto-update-mode)

Now, use the following keys:

M-.
To find the tag at point to jump to the function’s definition when the point is over a function call. It is a dwim-type function.
M-,
jump back to where you were.
M-?
find a tag, that is, use the Tags file to look up a definition. If there are multiple tags in the project with the same name, use `C-u M-.’ to go to the next match.
M-x tags-search
regexp-search through the source files indexed by a tags file (a bit like grep)
M-x tags-query-replace
query-replace through the source files indexed by a tags file
M-x tags-apropos
list all tags in a tags file that match a regexp
M-x list-tags
list all tags defined in a source file

Other helpful movement commands I need to remember:

  • C-M-a - Jump to the start of a function
  • C-M-e - Jump to the end of a function

Shell Scripts

Files in my bin directory (but only if it doesn’t have any other extension), should start in sh-mode:

(setq auto-mode-alist (append auto-mode-alist '(("/bin/" . sh-mode))))

Emacs Lisp

Sure, everything here is in Emacs Lisp, but this section helps me write more of that.

The most important change to Emacs Lisp is colorizing the variables:

(add-hook 'emacs-lisp-mode-hook 'color-identifiers-mode)

Paredit

One of the cooler features of Emacs is the ParEdit mode which keeps all parenthesis balanced in Lisp-oriented languages. See this cheatsheet.

(require 'paredit)

Associate the following Lisp-based modes with ParEdit:

(defun turn-on-paredit () (paredit-mode t))

Associate the following Lisp-based modes with ParEdit:

(add-hook 'emacs-lisp-mode-hook       'turn-on-paredit)
(add-hook 'lisp-mode-hook             'turn-on-paredit)
(add-hook 'lisp-interaction-mode-hook 'turn-on-paredit)
(add-hook 'scheme-mode-hook           'turn-on-paredit)
(add-hook 'clojure-mode-hook          'turn-on-paredit)
(add-hook 'cider-repl-mode-hook       'turn-on-paredit)
(add-hook 'sibiliant-mode-hook        'turn-on-paredit)

According to the ParEdit documentation, we can allow a Return keypress to insert a couple of indented newlines, if within an s-expression. While within paredit, simply press ) to shrink back up the extra whitespace.

(defun electrify-return-if-match (arg)
      "If the text after the cursor matches `electrify-return-match' then
    open and indent an empty line between the cursor and the text.  Move the
    cursor to the new line."
      (interactive "P")
      (let ((case-fold-search nil))
        (if (looking-at "[\]}\)\"]")
            (save-excursion (newline-and-indent)))
        (newline arg)
        (indent-according-to-mode)))

Finally, bind the function to a key:

(add-hook 'paredit-mode-hook
          (lambda ()
            (local-set-key (kbd "RET") 'electrify-return-if-match)))

Prettify Symbols

Might as well pretty up the lambdas, and other functions using the new 24.4 prettify-symbols-mode:

This approach seems to work and looks pretty good:

(when (fboundp 'global-prettify-symbols-mode)
    (defconst lisp--prettify-symbols-alist
      '(("lambda"  . )
        ("curry"   . )
        ("rcurry"  . )
        ("comp"    . ?∘)
        ("compose" . ?∘)
        ("."       . ?•)))

    (global-prettify-symbols-mode 1))

Words with dashes don’t separate words in Lisp:

(dolist (c (string-to-list ":_-?!#*"))
  (modify-syntax-entry c "w" emacs-lisp-mode-syntax-table))

Note:: Need to change this to work with the v24.4 super-word.

Insert Comment of Eval

While writing and documenting Emacs Lisp code, it would be helpful to insert the results of evaluation of an s-expression directly into the code as a comment:

(defun eval-and-comment-output ()
  "Add the output of the sexp as a comment after the sexp"
  (interactive)
  (save-excursion
    (end-of-line)
    (condition-case nil
        (princ (concat " ; -> " (pp-to-string (eval (preceding-sexp))))
               (current-buffer))
      (error (message "Invalid expression")))))

And since it is Emacs Lisp, let’s bind globally:

(global-set-key (kbd "C-x e") 'eval-and-comment-output)

Clojure

See emacs-clojure.el for details on working with Clojure. Not sure if I should just load it directly, like:

(require 'init-clojure)

Java

As soon as a I have a project that requires Java (and doesn’t allow me to work on either Clojure or Scala, I’ll update my old Java initialization section.

Ruby

See my emacs-ruby.el file for details on working with Ruby. Typically, my emacs-local.el file would do the work of requiring this for particular hosts or projects.

(require 'init-ruby)

Python

See emacs-python.el for details on working with Python. Not sure if I should just load it directly, like:

(require 'init-python)

JavaScript

See emacs-javascript.el for details on working with JavaScript.

(require 'init-javascript)

HTML, CSS and other Web Programming

See emacs-web.el for details on working with HTML and its ilk.

(require 'init-web)

Org-Mode

See emacs-org-mode.el for details on my Org-Mode settings.

(require 'init-org-mode)

Tools

Git

Git is already part of Emacs. However, Magit is sweet.

(require 'magit)

(global-set-key (kbd "C-x g") 'magit-status)
(define-key personal-global-map (kbd "g") 'magit-status)

Temporarily drop into Magit while looking at the file system (through the standard load-file) without actually loading a file.

(define-key ido-completion-map
  (kbd "C-x g") 'ido-enter-magit-status)

Full Screen Git

I like having Magit to run in a full screen mode, and took this defadvice idea from Sven Magnars:

(defadvice magit-status (around magit-fullscreen activate)
  (window-configuration-to-register :magit-fullscreen)
  ad-do-it
  (delete-other-windows))

Now, we have to have the q command recover the window session that was stored in a window register:

(defun magit-quit-session ()
  "Restores the previous window configuration and kills the magit buffer"
  (interactive)
  (kill-buffer)
  (jump-to-register :magit-fullscreen))

(define-key magit-status-mode-map (kbd "q") 'magit-quit-session)

Fringe Information

Install and use the Git Gutter Fringe to see what lines are dirty from Git’s perspective.

(if (window-system)
    (when (require 'git-gutter-fringe nil t)
      (global-git-gutter-mode +1)
      (setq-default indicate-buffer-boundaries 'left)
      (setq-default indicate-empty-lines +1)))

To see a blame mode, use either vc-annotate (C-x v g) or magit-blame-mode.

One-step Commits

Simple function to stage and commit the current file. Even asks to save the current file.

(defun ha/commit-file (&optional args)
  "Stage and commit the current file.  With a prefix argument, ARGS,
ammends the previous commit."
  (interactive "P")
  (magit-stage-file (buffer-file-name))
  (if args
      (magit-commit-amend)
    (magit-commit)))

(global-set-key (kbd "C-x G") 'ha/commit-file)

Github Pull Requests

Perhaps we can do Github pull requests from within Emacs, after reading this blog entry. Just do # g g in Magit to list the pull requests.

(when (require 'magit-gh-pulls nil t)
      (add-hook 'magit-mode-hook 'turn-on-magit-gh-pulls))

Markdown

Don’t use Markdown nearly as much as I used to, but I’m surprised that the following extension-associations aren’t the default:

(autoload 'markdown-mode "markdown-mode.el"
   "Major mode for editing Markdown files" t)
(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))

Using the surround function, I create some wrapper functions to make it easier to bold text in Markdown files:

(defun markdown-bold () "Wraps the region with double asterisks."
  (interactive)
  (surround-text "**"))
(defun markdown-italics () "Wraps the region with asterisks."
  (interactive)
  (surround-text "*"))
(defun markdown-code () "Wraps the region with equal signs."
  (interactive)
  (surround-text "`"))

Now I can associate some keystrokes to markdown-mode:

(add-hook 'markdown-mode-hook
      (lambda ()
        (local-set-key (kbd "A-b") 'markdown-bold)
        (local-set-key (kbd "s-b") 'markdown-bold)    ;; For Linux
        (local-set-key (kbd "A-i") 'markdown-italics)
        (local-set-key (kbd "s-i") 'markdown-italics)
        (local-set-key (kbd "A-=") 'markdown-code)
        (local-set-key (kbd "s-=") 'markdown-code)))

Wiki

Now that Atlassian changed this Wiki system so that confluence.el doesn’t work anymore (yeah, not an improvement, Atlassian), I can still use the confluence-edit-mode for anything with a .wiki extension.

(autoload 'confluence-edit-mode "confluence-edit-mode.el"
   "Major mode for editing Wiki documents" t)
(add-to-list 'auto-mode-alist '("\\.wiki\\'" . confluence-edit-mode))

I would also like to create and use some formatting wrappers.

(defun wiki-bold () "Wraps the region with single asterisks."
  (interactive)
  (surround-text "*"))
(defun wiki-italics () "Wraps the region with underbars."
  (interactive)
  (surround-text "_"))
(defun wiki-code () "Wraps the region with curly brackets."
  (interactive)
  (surround-text "{{" "}}"))

Now I can associate some keystrokes to markdown-mode:

(add-hook 'confluence-edit-mode-hook
      (lambda ()
        (local-set-key (kbd "A-b") 'wiki-bold)
        (local-set-key (kbd "A-i") 'wiki-italics)
        (local-set-key (kbd "A-=") 'wiki-code)))

PlantUML and Graphviz

Install the Graphviz project using Homebrew:

brew install graphviz
brew link graphviz
brew install plantuml

To get PlantUML working in Emacs, first, download the Jar and place in the ~/bin directory. We then set the “mode” working for editing the files:

(setq plantuml-jar-path (concat (getenv "HOME") "/bin/plantuml.jar"))

Second, to get PlantUML working in org-mode, set a different variable:

(setq org-plantuml-jar-path (concat (getenv "HOME") "/bin/plantuml.jar"))

Applications

Web Browsing

This section became involved, and has moved on to emacs-browser file.

(require 'init-browser)

EShell

See emacs-eshell.el for details of configuring and using EShell.

(require 'init-eshell)

Circe

I find reading Twitter and IRC in Emacs a good idea. Really. Small bits of the Emacs window are accessible and whatnot.

(require 'circe nil t)

Chatting

Using the jabber.el project to connect up to Google Talk and what not. To begin, make sure you brew install gnutls

(when (require 'jabber nil t)
  (setq starttls-use-gnutls t
        starttls-gnutls-program "gnutls-cli"
        starttls-extra-arguments '("--starttls" "--insecure"))
  (setq
   jabber-history-enabled t
   jabber-use-global-history nil
   jabber-backlog-number 40
   jabber-backlog-days 30)

  (defun my-jabber-chat-delete-or-bury ()
    (interactive)
    (if (eq 'jabber-chat-mode major-mode)
        (condition-case e
            (delete-frame)
          (error
           (if (string= "Attempt to delete the sole visible or iconified frame"
                        (cadr e))
               (bury-buffer))))))

  (define-key jabber-chat-mode-map [escape]
    'my-jabber-chat-delete-or-bury)

  (when (require 'autosmiley nil t)
    (add-hook 'jabber-chat-mode-hook 'autosmiley-mode)))

To chat simply press: C-x C-j C-c … hahaha. I doubt I can remember that one. Perhaps.

Technical Artifacts

Setting up the Exec Path

Make sure that PATH variable for finding binary files can is the same as what Emacs will look for binary files. This little magic, starts up a shell, gets its path, and then uses that for the exec-path:

(when window-system
  (let ((path-from-shell (shell-command-to-string "/bin/bash -l -c 'echo $PATH'")))
    (setenv "PATH" path-from-shell)
    (setq exec-path (split-string path-from-shell path-separator))))

Configure the Graphical Settings

If we are running in a windowed environment where we can set up fonts and whatnot, call the ‘mac’ stuff… which will still work for Linux too.

(if (window-system)
   (require 'init-client)
 (require 'init-server))

Load up the Local Configuration

Before we finish, we need to check if there is a local file for us to load and evaluate. We assume the local file has been tangled and provides the init-local key:

(require 'init-local nil t)

After the first load, we can reload this with a require:

(provide 'init-main)

Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: C-c C-c