From 2e1087a7a81acc6c2a509c4fbd6e20a7aba73b0e Mon Sep 17 00:00:00 2001
From: Anna Wiggins <awiggins@roostify.com>
Date: Fri, 17 Mar 2017 15:06:51 -0700
Subject: [PATCH] Clean up old cruft, add some modules.

---
 emacs                         |   22 +-
 emacs.d/lisp/markdown-mode.el | 5978 +++++++++++++++++++++++++++++++++
 emacs.d/lisp/yaml-mode.el     |  439 +++
 3 files changed, 6425 insertions(+), 14 deletions(-)
 create mode 100644 emacs.d/lisp/markdown-mode.el
 create mode 100644 emacs.d/lisp/yaml-mode.el

diff --git a/emacs b/emacs
index 62f5d84..c42ca7c 100755
--- a/emacs
+++ b/emacs
@@ -30,8 +30,6 @@
 
 ;; Kill GUI elements
 (menu-bar-mode 0)
-(tool-bar-mode 0)
-(scroll-bar-mode -1)
 
 ;; *** Programming
 (global-set-key (kbd "C-x g") 'goto-line)
@@ -44,21 +42,17 @@
 (setq-default css-indent-offset 2)
 (column-number-mode)
 
-;; Git support
-(add-to-list 'load-path "/usr/share/doc/git/contrib/emacs")
-(require 'git)
-(require 'git-blame)
+;; Use the right mode for Arduino sketches
+(add-to-list 'auto-mode-alist '("\\.ino\\'" . c++-mode))
 
-;; Markdown support (requires emacs-goodies)
+(add-to-list 'load-path "~/.emacs.d/lisp")
+(require 'yaml-mode)
+(require 'slim-mode)
+(require 'haml-mode)
+
+;; Markdown support
 (autoload 'markdown-mode "markdown-mode"
    "Major mode for editing Markdown files" t)
 (add-to-list 'auto-mode-alist '("\\.text\\'" . markdown-mode))
 (add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
 (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
-
-;; Use the right mode for Arduino sketches
-(add-to-list 'auto-mode-alist '("\\.ino\\'" . c++-mode))
-
-(add-to-list 'load-path "~/.emacs.d/lisp")
-(require 'slim-mode)
-(require 'haml-mode)
diff --git a/emacs.d/lisp/markdown-mode.el b/emacs.d/lisp/markdown-mode.el
new file mode 100644
index 0000000..fcef2db
--- /dev/null
+++ b/emacs.d/lisp/markdown-mode.el
@@ -0,0 +1,5978 @@
+;;; markdown-mode.el --- Emacs Major mode for Markdown-formatted text files
+
+;; Copyright (C) 2007-2016 Jason R. Blevins <jrblevin@sdf.org>
+;; Copyright (C) 2007, 2009 Edward O'Connor <ted@oconnor.cx>
+;; Copyright (C) 2007 Conal Elliott <conal@conal.net>
+;; Copyright (C) 2008 Greg Bognar <greg_bognar@hms.harvard.edu>
+;; Copyright (C) 2008 Dmitry Dzhus <mail@sphinx.net.ru>
+;; Copyright (C) 2008 Bryan Kyle <bryan.kyle@gmail.com>
+;; Copyright (C) 2008 Ben Voui <intrigeri@boum.org>
+;; Copyright (C) 2009 Ankit Solanki <ankit.solanki@gmail.com>
+;; Copyright (C) 2009 Hilko Bengen <bengen@debian.org>
+;; Copyright (C) 2009 Peter Williams <pezra@barelyenough.org>
+;; Copyright (C) 2010 George Ogata <george.ogata@gmail.com>
+;; Copyright (C) 2011 Eric Merritt <ericbmerritt@gmail.com>
+;; Copyright (C) 2011 Philippe Ivaldi <pivaldi@sfr.fr>
+;; Copyright (C) 2011 Jeremiah Dodds <jeremiah.dodds@gmail.com>
+;; Copyright (C) 2011 Christopher J. Madsen <cjm@cjmweb.net>
+;; Copyright (C) 2011 Shigeru Fukaya <shigeru.fukaya@gmail.com>
+;; Copyright (C) 2011 Joost Kremers <joostkremers@fastmail.fm>
+;; Copyright (C) 2011-2012 Donald Ephraim Curtis <dcurtis@milkbox.net>
+;; Copyright (C) 2012 Akinori Musha <knu@idaemons.org>
+;; Copyright (C) 2012 Zhenlei Jia <zhenlei.jia@gmail.com>
+;; Copyright (C) 2012 Peter Jones <pjones@pmade.com>
+;; Copyright (C) 2013 Matus Goljer <dota.keys@gmail.com>
+;; Copyright (C) 2015 Google, Inc. (Contributor: Samuel Freilich <sfreilich@google.com>)
+;; Copyright (C) 2015 Antonis Kanouras <antonis@metadosis.gr>
+;; Copyright (C) 2015 Howard Melman <hmelman@gmail.com>
+;; Copyright (C) 2015-2016 Danny McClanahan <danieldmcclanahan@gmail.com>
+
+;; Author: Jason R. Blevins <jrblevin@sdf.org>
+;; Maintainer: Jason R. Blevins <jrblevin@sdf.org>
+;; Created: May 24, 2007
+;; Version: 2.1
+;; Package-Requires: ((cl-lib "0.5"))
+;; Keywords: Markdown, GitHub Flavored Markdown, itex
+;; URL: http://jblevins.org/projects/markdown-mode/
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;; Commentary:
+
+;; markdown-mode is a major mode for editing [Markdown][]-formatted
+;; text files in GNU Emacs.  markdown-mode is free software, licensed
+;; under the GNU GPL.
+;;
+;;  [Markdown]: http://daringfireball.net/projects/markdown/
+;;
+;; The latest stable version is markdown-mode 2.1, released on January 9, 2016:
+;;
+;;    * [markdown-mode.el][]
+;;    * [Screenshot][][^theme]
+;;    * [Release notes][]
+;;
+;;  [markdown-mode.el]: http://jblevins.org/projects/markdown-mode/markdown-mode.el
+;;  [Screenshot]: http://jblevins.org/projects/markdown-mode/screenshots/20160108-001.png
+;;  [Release notes]: http://jblevins.org/projects/markdown-mode/rev-2-1
+;;
+;; [^theme]: The theme used in the screenshot is
+;;     [color-theme-twilight](https://github.com/crafterm/twilight-emacs).
+;;
+;; The latest development version can be obtained from the Git
+;; repository at <http://jblevins.org/git/markdown-mode.git> or from
+;; [GitHub][]:
+;;
+;;     git clone git://jblevins.org/git/markdown-mode.git
+;;     git clone https://github.com/jrblevin/markdown-mode.git
+;;
+;; [![Build Status][status]][travis]
+;;
+;;  [devel.el]: http://jblevins.org/git/markdown-mode.git/plain/markdown-mode.el
+;;  [GitHub]: https://github.com/jrblevin/markdown-mode/
+;;  [travis]: https://travis-ci.org/jrblevin/markdown-mode
+;;  [status]: https://travis-ci.org/jrblevin/markdown-mode.svg?branch=master
+;;
+;; markdown-mode is also available in several package managers, including:
+;;
+;;    * Debian Linux: [elpa-markdown-mode][] and [emacs-goodies-el][]
+;;    * Ubuntu Linux: [elpa-markdown-mode][elpa-ubuntu] and [emacs-goodies-el][emacs-goodies-el-ubuntu]
+;;    * RedHat and Fedora Linux: [emacs-goodies][]
+;;    * NetBSD: [textproc/markdown-mode][]
+;;    * Arch Linux (AUR): [emacs-markdown-mode-git][]
+;;    * MacPorts: [markdown-mode.el][macports-package] ([pending][macports-ticket])
+;;    * FreeBSD: [textproc/markdown-mode.el][freebsd-port]
+;;
+;;  [elpa-markdown-mode]: https://packages.debian.org/sid/lisp/elpa-markdown-mode
+;;  [elpa-ubuntu]: http://packages.ubuntu.com/search?keywords=elpa-markdown-mode
+;;  [emacs-goodies-el]: http://packages.debian.org/emacs-goodies-el
+;;  [emacs-goodies-el-ubuntu]: http://packages.ubuntu.com/search?keywords=emacs-goodies-el
+;;  [emacs-goodies]: https://apps.fedoraproject.org/packages/emacs-goodies
+;;  [textproc/markdown-mode]: http://pkgsrc.se/textproc/markdown-mode
+;;  [emacs-markdown-mode-git]: https://aur.archlinux.org/packages/emacs-goodies-el/
+;;  [macports-package]: https://trac.macports.org/browser/trunk/dports/editors/markdown-mode.el/Portfile
+;;  [macports-ticket]: http://trac.macports.org/ticket/35716
+;;  [freebsd-port]: http://svnweb.freebsd.org/ports/head/textproc/markdown-mode.el
+
+;;; Installation:
+
+;; Make sure to place `markdown-mode.el` somewhere in the load-path and add
+;; the following lines to your `.emacs` file to associate markdown-mode
+;; with `.text`, `.markdown`, and `.md` files:
+;;
+;;     (autoload 'markdown-mode "markdown-mode"
+;;        "Major mode for editing Markdown files" t)
+;;     (add-to-list 'auto-mode-alist '("\\.text\\'" . markdown-mode))
+;;     (add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
+;;     (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
+;;
+;; There is no official Markdown file extension, nor is there even a
+;; _de facto_ standard, so you can easily add, change, or remove any
+;; of the file extensions above as needed.
+;;
+;; `markdown-mode' depends on `cl-lib', which has been bundled with
+;; GNU Emacs since 24.3.  Users of GNU Emacs 24.1 and 24.2 can install
+;; `cl-lib' with `package.el'.
+
+;;; Usage:
+
+;; Keybindings are grouped by prefixes based on their function.  For
+;; example, the commands for inserting links are grouped under `C-c
+;; C-a`, where the `C-a` is a mnemonic for the HTML `<a>` tag.  In
+;; other cases, the connection to HTML is not direct.  For example,
+;; commands dealing with headings begin with `C-c C-t` (mnemonic:
+;; titling).  The primary commands in each group will are described
+;; below.  You can obtain a list of all keybindings by pressing `C-c
+;; C-h`.  Movement and shifting commands tend to be associated with
+;; paired delimiters such as `M-{` and `M-}` or `C-c <` and `C-c >`.
+;; Outline navigation keybindings the same as in `org-mode'.  Finally,
+;; commands for running Markdown or doing maintenance on an open file
+;; are grouped under the `C-c C-c` prefix.  The most commonly used
+;; commands are described below.  You can obtain a list of all
+;; keybindings by pressing `C-c C-h`.
+;;
+;;   * Hyperlinks: `C-c C-a`
+;;
+;;     In this group, `C-c C-a l` inserts an inline link of the form
+;;     `[text](url)`.  The link text is determined as follows.  First,
+;;     if there is an active region (i.e., when transient mark mode is
+;;     on and the mark is active), use it as the link text.  Second,
+;;     if the point is at a word, use that word as the link text.  In
+;;     these two cases, the original text will be replaced with the
+;;     link and point will be left at the position for inserting a
+;;     URL.  Otherwise, insert empty link markup and place the point
+;;     for inserting the link text.
+;;
+;;     `C-c C-a L` inserts a reference link of the form `[text][label]`
+;;     and, optionally, a corresponding reference label definition.
+;;     The link text is determined in the same way as with an inline
+;;     link (using the region, when active, or the word at the point),
+;;     but instead of inserting empty markup as a last resort, the
+;;     link text will be read from the minibuffer.  The reference
+;;     label will be read from the minibuffer in both cases, with
+;;     completion from the set of currently defined references.  To
+;;     create an implicit reference link, press `RET` to accept the
+;;     default, an empty label.  If the entered referenced label is
+;;     not defined, additionally prompt for the URL and (optional)
+;;     title.  If a URL is provided, a reference definition will be
+;;     inserted in accordance with `markdown-reference-location'.
+;;     If a title is given, it will be added to the end of the
+;;     reference definition and will be used to populate the title
+;;     attribute when converted to XHTML.
+;;
+;;     `C-c C-a u` inserts a bare url, delimited by angle brackets.  When
+;;     there is an active region, the text in the region is used as the
+;;     URL.  If the point is at a URL, that url is used.  Otherwise,
+;;     insert angle brackets and position the point in between them
+;;     for inserting the URL.
+;;
+;;     `C-c C-a f` inserts a footnote marker at the point, inserts a
+;;     footnote definition below, and positions the point for
+;;     inserting the footnote text.  Note that footnotes are an
+;;     extension to Markdown and are not supported by all processors.
+;;
+;;     `C-c C-a w` behaves much like the inline link insertion command
+;;     and inserts a wiki link of the form `[[WikiLink]]`.  If there
+;;     is an active region, use the region as the link text.  If the
+;;     point is at a word, use the word as the link text.  If there is
+;;     no active region and the point is not at word, simply insert
+;;     link markup.  Note that wiki links are an extension to Markdown
+;;     and are not supported by all processors.
+;;
+;;   * Images: `C-c C-i`
+;;
+;;     `C-c C-i i` inserts markup for an inline image, using the
+;;     active region or the word at point, if any, as the alt text.
+;;     `C-c C-i I` behaves similarly and inserts a reference-style
+;;     image.
+;;
+;;   * Styles: `C-c C-s`
+;;
+;;     `C-c C-s e` inserts markup to make a region or word italic (`e`
+;;     for `<em>` or emphasis).  If there is an active region, make
+;;     the region italic.  If the point is at a non-italic word, make
+;;     the word italic.  If the point is at an italic word or phrase,
+;;     remove the italic markup.  Otherwise, simply insert italic
+;;     delimiters and place the cursor in between them.  Similarly,
+;;     use `C-c C-s s` for bold (`<strong>`) and `C-c C-s c` for
+;;     inline code (`<code>`).
+;;
+;;     `C-c C-s b` inserts a blockquote using the active region, if any,
+;;     or starts a new blockquote.  `C-c C-s C-b` is a variation which
+;;     always operates on the region, regardless of whether it is
+;;     active or not.  The appropriate amount of indentation, if any,
+;;     is calculated automatically given the surrounding context, but
+;;     may be adjusted later using the region indentation commands.
+;;
+;;     `C-c C-s p` behaves similarly for inserting preformatted code
+;;     blocks, with `C-c C-s C-p` being the region-only counterpart.
+;;
+;;   * Headings: `C-c C-t`
+;;
+;;     All heading insertion commands use the text in the active
+;;     region, if any, as the heading text.  Otherwise, if the current
+;;     line is not blank, they use the text on the current line.
+;;     Finally, the setext commands will prompt for heading text if
+;;     there is no active region and the current line is blank.
+;;
+;;     `C-c C-t h` inserts a heading with automatically chosen type and
+;;     level (both determined by the previous heading).  `C-c C-t H`
+;;     behaves similarly, but uses setext (underlined) headings when
+;;     possible, still calculating the level automatically.
+;;     In cases where the automatically-determined level is not what
+;;     you intended, the level can be quickly promoted or demoted
+;;     (as described below).  Alternatively, a `C-u` prefix can be
+;;     given to insert a heading promoted by one level or a `C-u C-u`
+;;     prefix can be given to insert a heading demoted by one level.
+;;
+;;     To insert a heading of a specific level and type, use `C-c C-t 1`
+;;     through `C-c C-t 6` for atx (hash mark) headings and `C-c C-t !` or
+;;     `C-c C-t @` for setext headings of level one or two, respectively.
+;;     Note that `!` is `S-1` and `@` is `S-2`.
+;;
+;;     If the point is at a heading, these commands will replace the
+;;     existing markup in order to update the level and/or type of the
+;;     heading.  To remove the markup of the heading at the point,
+;;     press `C-c C-k` to kill the heading and press `C-y` to yank the
+;;     heading text back into the buffer.
+;;
+;;   * Horizontal Rules: `C-c -`
+;;
+;;     `C-c -` inserts a horizontal rule.  By default, insert the
+;;     first string in the list `markdown-hr-strings' (the most
+;;     prominent rule).  With a `C-u` prefix, insert the last string.
+;;     With a numeric prefix `N`, insert the string in position `N`
+;;     (counting from 1).
+;;
+;;   * Markdown and Maintenance Commands: `C-c C-c`
+;;
+;;     *Compile:* `C-c C-c m` will run Markdown on the current buffer
+;;     and show the output in another buffer.  *Preview*: `C-c C-c p`
+;;     runs Markdown on the current buffer and previews, stores the
+;;     output in a temporary file, and displays the file in a browser.
+;;     *Export:* `C-c C-c e` will run Markdown on the current buffer
+;;     and save the result in the file `basename.html`, where
+;;     `basename` is the name of the Markdown file with the extension
+;;     removed.  *Export and View:* press `C-c C-c v` to export the
+;;     file and view it in a browser.  *Open:* `C-c C-c o` will open
+;;     the Markdown source file directly using `markdown-open-command'.
+;;     *Live Export*: Press `C-c C-c l` to turn on
+;;     `markdown-live-preview-mode' to view the exported output
+;;     side-by-side with the source Markdown. **For all export commands,
+;;     the output file will be overwritten without notice.**
+;;     `markdown-live-preview-window-function' can be customized to open
+;;     in a browser other than `eww'.
+;;
+;;     To summarize:
+;;
+;;       - `C-c C-c m`: `markdown-command' > `*markdown-output*` buffer.
+;;       - `C-c C-c p`: `markdown-command' > temporary file > browser.
+;;       - `C-c C-c e`: `markdown-command' > `basename.html`.
+;;       - `C-c C-c v`: `markdown-command' > `basename.html` > browser.
+;;       - `C-c C-c w`: `markdown-command' > kill ring.
+;;       - `C-c C-c o`: `markdown-open-command'.
+;;       - `C-c C-c l`: `markdown-live-preview-mode' > `*eww*` buffer.
+;;
+;;     `C-c C-c c` will check for undefined references.  If there are
+;;     any, a small buffer will open with a list of undefined
+;;     references and the line numbers on which they appear.  In Emacs
+;;     22 and greater, selecting a reference from this list and
+;;     pressing `RET` will insert an empty reference definition at the
+;;     end of the buffer.  Similarly, selecting the line number will
+;;     jump to the corresponding line.
+;;
+;;     `C-c C-c n` renumbers any ordered lists in the buffer that are
+;;     out of sequence.
+;;
+;;     `C-c C-c ]` completes all headings and normalizes all horizontal
+;;     rules in the buffer.
+;;
+;;   * Following Links: `C-c C-o`
+;;
+;;     Press `C-c C-o` when the point is on an inline or reference
+;;     link to open the URL in a browser.  When the point is at a
+;;     wiki link, open it in another buffer (in the current window,
+;;     or in the other window with the `C-u` prefix).  Use `M-p` and
+;;     `M-n` to quickly jump to the previous or next link of any type.
+;;
+;;   * Jumping: `C-c C-j`
+;;
+;;     Use `C-c C-j` to jump from the object at point to its counterpart
+;;     elsewhere in the text, when possible.  Jumps between reference
+;;     links and definitions; between footnote markers and footnote
+;;     text.  If more than one link uses the same reference name, a
+;;     new buffer will be created containing clickable buttons for jumping
+;;     to each link.  You may press `TAB` or `S-TAB` to jump between
+;;     buttons in this window.
+;;
+;;   * Promotion and Demotion: `C-c C--` and `C-c C-=`
+;;
+;;     Headings, horizontal rules, and list items can be promoted and
+;;     demoted, as well as bold and italic text.  For headings,
+;;     "promotion" means *decreasing* the level (i.e., moving from
+;;     `<h2>` to `<h1>`) while "demotion" means *increasing* the
+;;     level.  For horizontal rules, promotion and demotion means
+;;     moving backward or forward through the list of rule strings in
+;;     `markdown-hr-strings'.  For bold and italic text, promotion and
+;;     demotion means changing the markup from underscores to asterisks.
+;;     Press `C-c C--` or `M-LEFT` to promote the element at the point
+;;     if possible.
+;;
+;;     To remember these commands, note that `-` is for decreasing the
+;;     level (promoting), and `=` (on the same key as `+`) is for
+;;     increasing the level (demoting).  Similarly, the left and right
+;;     arrow keys indicate the direction that the atx heading markup
+;;     is moving in when promoting or demoting.
+;;
+;;   * Completion: `C-c C-]`
+;;
+;;     Complete markup is in normalized form, which means, for
+;;     example, that the underline portion of a setext header is the
+;;     same length as the heading text, or that the number of leading
+;;     and trailing hash marks of an atx header are equal and that
+;;     there is no extra whitespace in the header text.  `C-c C-]`
+;;     completes the markup at the point, if it is determined to be
+;;     incomplete.
+;;
+;;   * Editing Lists: `M-RET`, `M-UP`, `M-DOWN`, `M-LEFT`, and `M-RIGHT`
+;;
+;;     New list items can be inserted with `M-RET`.  This command
+;;     determines the appropriate marker (one of the possible
+;;     unordered list markers or the next number in sequence for an
+;;     ordered list) and indentation level by examining nearby list
+;;     items.  If there is no list before or after the point, start a
+;;     new list.  Prefix this command by `C-u` to decrease the
+;;     indentation by one level.  Prefix this command by `C-u C-u` to
+;;     increase the indentation by one level.
+;;
+;;     Existing list items can be moved up or down with `M-UP` or
+;;     `M-DOWN` and indented or exdented with `M-RIGHT` or `M-LEFT`.
+;;
+;;   * Editing Subtrees: `M-S-UP`, `M-S-DOWN`, `M-S-LEFT`, and `M-S-RIGHT`
+;;
+;;     Entire subtrees of ATX headings can be promoted and demoted
+;;     with `M-S-LEFT` and `M-S-RIGHT`, which mirror the bindings
+;;     for promotion and demotion of list items. Similarly, subtrees
+;;     can be moved up and down with `M-S-UP` and `M-S-DOWN`.
+;;
+;;     Please note the following "boundary" behavior for promotion and
+;;     demotion.  Any level-six headings will not be demoted further
+;;     (i.e., they remain at level six, since Markdown and HTML define
+;;     only six levels) and any level-one headings will promoted away
+;;     entirely (i.e., heading markup will be removed, since a
+;;     level-zero heading is not defined).
+;;
+;;   * Shifting the Region: `C-c <` and `C-c >`
+;;
+;;     Text in the region can be indented or exdented as a group using
+;;     `C-c >` to indent to the next indentation point (calculated in
+;;     the current context), and `C-c <` to exdent to the previous
+;;     indentation point.  These keybindings are the same as those for
+;;     similar commands in `python-mode'.
+;;
+;;   * Killing Elements: `C-c C-k`
+;;
+;;     Press `C-c C-k` to kill the thing at point and add important
+;;     text, without markup, to the kill ring.  Possible things to
+;;     kill include (roughly in order of precedece): inline code,
+;;     headings, horizonal rules, links (add link text to kill ring),
+;;     images (add alt text to kill ring), angle URIs, email
+;;     addresses, bold, italics, reference definitions (add URI to
+;;     kill ring), footnote markers and text (kill both marker and
+;;     text, add text to kill ring), and list items.
+;;
+;;   * Outline Navigation: `C-c C-n`, `C-c C-p`, `C-c C-f`, `C-c C-b`, and `C-c C-u`
+;;
+;;     Navigation between headings is possible using `outline-mode'.
+;;     Use `C-c C-n` and `C-c C-p` to move between the next and previous
+;;     visible headings.  Similarly, `C-c C-f` and `C-c C-b` move to the
+;;     next and previous visible headings at the same level as the one
+;;     at the point.  Finally, `C-c C-u` will move up to a lower-level
+;;     (higher precedence) visible heading.
+;;
+;;   * Movement by Paragraph or Block: `M-{` and `M-}`
+;;
+;;     The definition of a "paragraph" is slightly different in
+;;     markdown-mode than, say, text-mode, because markdown-mode
+;;     supports filling for list items and respects hard line breaks,
+;;     both of which break paragraphs.  So, markdown-mode overrides
+;;     the usual paragraph navigation commands `M-{` and `M-}` so that
+;;     with a `C-u` prefix, these commands jump to the beginning or
+;;     end of an entire block of text, respectively, where "blocks"
+;;     are separated by one or more lines.
+;;
+;;   * Movement by Defun: `C-M-a`, `C-M-e`, and `C-M-h`
+;;
+;;     The usual Emacs commands can be used to move by defuns
+;;     (top-level major definitions).  In markdown-mode, a defun is a
+;;     section.  As usual, `C-M-a` will move the point to the
+;;     beginning of the current or preceding defun, `C-M-e` will move
+;;     to the end of the current or following defun, and `C-M-h` will
+;;     put the region around the entire defun.
+;;
+;; As noted, many of the commands above behave differently depending
+;; on whether Transient Mark mode is enabled or not.  When it makes
+;; sense, if Transient Mark mode is on and the region is active, the
+;; command applies to the text in the region (e.g., `C-c C-s s` makes the
+;; region bold).  For users who prefer to work outside of Transient
+;; Mark mode, since Emacs 22 it can be enabled temporarily by pressing
+;; `C-SPC C-SPC`.  When this is not the case, many commands then
+;; proceed to look work with the word or line at the point.
+;;
+;; When applicable, commands that specifically act on the region even
+;; outside of Transient Mark mode have the same keybinding as their
+;; standard counterpart, but the letter is uppercase.  For example,
+;; `markdown-insert-blockquote' is bound to `C-c C-s b` and only acts on
+;; the region in Transient Mark mode while `markdown-blockquote-region'
+;; is bound to `C-c C-s B` and always applies to the region (when nonempty).
+;;
+;; Note that these region-specific functions are useful in many
+;; cases where it may not be obvious.  For example, yanking text from
+;; the kill ring sets the mark at the beginning of the yanked text
+;; and moves the point to the end.  Therefore, the (inactive) region
+;; contains the yanked text.  So, `C-y` followed by `C-c C-s C-b` will
+;; yank text and turn it into a blockquote.
+;;
+;; markdown-mode attempts to be flexible in how it handles
+;; indentation.  When you press `TAB` repeatedly, the point will cycle
+;; through several possible indentation levels corresponding to things
+;; you might have in mind when you press `RET` at the end of a line or
+;; `TAB`.  For example, you may want to start a new list item,
+;; continue a list item with hanging indentation, indent for a nested
+;; pre block, and so on.  Exdention is handled similarly when backspace
+;; is pressed at the beginning of the non-whitespace portion of a line.
+;;
+;; markdown-mode supports outline-minor-mode as well as org-mode-style
+;; visibility cycling for atx- or hash-style headings.  There are two
+;; types of visibility cycling: Pressing `S-TAB` cycles globally between
+;; the table of contents view (headings only), outline view (top-level
+;; headings only), and the full document view.  Pressing `TAB` while the
+;; point is at a heading will cycle through levels of visibility for the
+;; subtree: completely folded, visible children, and fully visible.
+;; Note that mixing hash and underline style headings will give undesired
+;; results.
+
+;;; Customization:
+
+;; Although no configuration is *necessary* there are a few things
+;; that can be customized.  The `M-x customize-mode` command
+;; provides an interface to all of the possible customizations:
+;;
+;;   * `markdown-command' - the command used to run Markdown (default:
+;;     `markdown`).  This variable may be customized to pass
+;;     command-line options to your Markdown processor of choice.
+;;
+;;   * `markdown-command-needs-filename' - set to `t' if
+;;     `markdown-command' does not accept standard input (default:
+;;     `nil').  When `nil', `markdown-mode' will pass the Markdown
+;;     content to `markdown-command' using standard input (`stdin`).
+;;     When set to `t', `markdown-mode' will pass the name of the file
+;;     as the final command-line argument to `markdown-command'.  Note
+;;     that in the latter case, you will only be able to run
+;;     `markdown-command' from buffers which are visiting a file.
+;;
+;;   * `markdown-open-command' - the command used for calling a standalone
+;;     Markdown previewer which is capable of opening Markdown source files
+;;     directly (default: `nil').  This command will be called
+;;     with a single argument, the filename of the current buffer.
+;;     A representative program is the Mac app [Marked 2][], a
+;;     live-updating Markdown previewer which can be [called from a
+;;     simple shell script](http://jblevins.org/log/marked-2-command).
+;;
+;;   * `markdown-hr-strings' - list of strings to use when inserting
+;;     horizontal rules.  Different strings will not be distinguished
+;;     when converted to HTML--they will all be converted to
+;;     `<hr/>`--but they may add visual distinction and style to plain
+;;     text documents.  To maintain some notion of promotion and
+;;     demotion, keep these sorted from largest to smallest.
+;;
+;;   * `markdown-bold-underscore' - set to a non-nil value to use two
+;;     underscores for bold instead of two asterisks (default: `nil').
+;;
+;;   * `markdown-italic-underscore' - set to a non-nil value to use
+;;     underscores for italic instead of asterisks (default: `nil').
+;;
+;;   * `markdown-asymmetric-header' - set to a non-nil value to use
+;;     asymmetric header styling, placing header characters only on
+;;     the left of headers (default: `nil').
+;;
+;;   * `markdown-list-indent-width' - depth of indentation for lists
+;;     when inserting, promoting, and demoting list items (default: 4).
+;;
+;;   * `markdown-indent-function' - the function to use for automatic
+;;     indentation (default: `markdown-indent-line').
+;;
+;;   * `markdown-indent-on-enter' - set to a non-nil value to
+;;     automatically indent new lines when the enter key is pressed
+;;     (default: `t')
+;;
+;;   * `markdown-wiki-link-alias-first' - set to a non-nil value to
+;;     treat aliased wiki links like `[[link text|PageName]]`
+;;     (default: `t').  When set to nil, they will be treated as
+;;     `[[PageName|link text]]'.
+;;
+;;   * `markdown-uri-types' - a list of protocol schemes (e.g., "http")
+;;     for URIs that `markdown-mode' should highlight.
+;;
+;;   * `markdown-enable-math' - syntax highlighting for LaTeX
+;;     fragments (default: `nil').  Set this to `t' to turn on math
+;;     support by default.  Math support can be toggled later using
+;;     the function `markdown-enable-math'."
+;;
+;;   * `markdown-css-paths' - CSS files to link to in XHTML output
+;;     (default: `nil`).
+;;
+;;   * `markdown-content-type' - when set to a nonempty string, an
+;;     `http-equiv` attribute will be included in the XHTML `<head>`
+;;     block (default: `""`).  If needed, the suggested values are
+;;     `application/xhtml+xml` or `text/html`.  See also:
+;;     `markdown-coding-system'.
+;;
+;;   * `markdown-coding-system' - used for specifying the character
+;;     set identifier in the `http-equiv` attribute when included
+;;     (default: `nil').  See `markdown-content-type', which must
+;;     be set before this variable has any effect.  When set to `nil',
+;;     `buffer-file-coding-system' will be used to automatically
+;;     determine the coding system string (falling back to
+;;     `iso-8859-1' when unavailable).  Common settings are `utf-8'
+;;     and `iso-latin-1'.
+;;
+;;   * `markdown-xhtml-header-content' - additional content to include
+;;     in the XHTML `<head>` block (default: `""`).
+;;
+;;   * `markdown-xhtml-standalone-regexp' - a regular expression which
+;;     `markdown-mode' uses to determine whether the output of
+;;     `markdown-command' is a standalone XHTML document or an XHTML
+;;     fragment (default: `"^\\(<\\?xml\\|<!DOCTYPE\\|<html\\)"`).  If
+;;     this regular expression not matched in the first five lines of
+;;     output, `markdown-mode' assumes the output is a fragment and
+;;     adds a header and footer.
+;;
+;;   * `markdown-link-space-sub-char' - a character to replace spaces
+;;     when mapping wiki links to filenames (default: `"_"`).
+;;     For example, use an underscore for compatibility with the
+;;     Python Markdown WikiLinks extension.  In `gfm-mode', this is
+;;     set to `"-"` to conform with GitHub wiki links.
+;;
+;;   * `markdown-reference-location' - where to insert reference
+;;     definitions (default: `header`).  The possible locations are
+;;     the end of the document (`end`), after the current block
+;;     (`immediately`), before the next header (`header`).
+;;
+;;   * `markdown-footnote-location' - where to insert footnote text
+;;     (default: `end`).  The set of location options is the same as
+;;     for `markdown-reference-location'.
+;;
+;;   * `comment-auto-fill-only-comments' - variable is made
+;;     buffer-local and set to `nil' by default.  In programming
+;;     language modes, when this variable is non-nil, only comments
+;;     will be filled by auto-fill-mode.  However, comments in
+;;     Markdown documents are rare and the most users probably intend
+;;     for the actual content of the document to be filled.  Making
+;;     this variable buffer-local allows `markdown-mode' to override
+;;     the default behavior induced when the global variable is non-nil.
+;;
+;;   * `markdown-gfm-additional-languages', - additional languages to
+;;     make available, aside from those predefined in
+;;     `markdown-gfm-recognized-languages', when inserting GFM code
+;;     blocks (default: `nil`). Language strings must have be trimmed
+;;     of whitespace and not contain any curly braces. They may be of
+;;     arbitrary capitalization, though.
+;;
+;;   * `markdown-gfm-use-electric-backquote' - use
+;;     `markdown-electric-backquote' for interactive insertion of GFM
+;;     code blocks when backquote is pressed three times (default: `t`).
+;;
+;;   * `markdown-make-gfm-checkboxes-buttons' - Whether GitHub
+;;     Flavored Markdown style task lists (checkboxes) should be
+;;     turned into buttons that can be toggled with mouse-1 or RET. If
+;;     non-nil (default), then buttons are enabled.  This works in
+;;     `markdown-mode' as well as `gfm-mode'.
+;;
+;; Additionally, the faces used for syntax highlighting can be modified to
+;; your liking by issuing `M-x customize-group RET markdown-faces`
+;; or by using the "Markdown Faces" link at the bottom of the mode
+;; customization screen.
+;;
+;; [Marked 2]: https://itunes.apple.com/us/app/marked-2/id890031187?mt=12&uo=4&at=11l5Vs&ct=mm
+
+;;; Extensions:
+
+;; Besides supporting the basic Markdown syntax, markdown-mode also
+;; includes syntax highlighting for `[[Wiki Links]]` by default.  Wiki
+;; links may be followed by pressing `C-c C-o` when the point
+;; is at a wiki link.  Use `M-p` and `M-n` to quickly jump to the
+;; previous and next links (including links of other types).
+;; Aliased or piped wiki links of the form `[[link text|PageName]]`
+;; are also supported.  Since some wikis reverse these components, set
+;; `markdown-wiki-link-alias-first' to nil to treat them as
+;; `[[PageName|link text]]`.  By default, Markdown Mode only searches
+;; for target files in the current directory.  Sequential parent
+;; directory search (as in [Ikiwiki][]) can be enabled by setting
+;; `markdown-wiki-link-search-parent-directories' to a non-nil value.
+;;
+;; [Ikiwiki]: https://ikiwiki.info
+;;
+;; [SmartyPants][] support is possible by customizing `markdown-command'.
+;; If you install `SmartyPants.pl` at, say, `/usr/local/bin/smartypants`,
+;; then you can set `markdown-command' to `"markdown | smartypants"`.
+;; You can do this either by using `M-x customize-group markdown`
+;; or by placing the following in your `.emacs` file:
+;;
+;;     (setq markdown-command "markdown | smartypants")
+;;
+;; [SmartyPants]: http://daringfireball.net/projects/smartypants/
+;;
+;; Syntax highlighting for mathematical expressions written
+;; in LaTeX (only expressions denoted by `$..$`, `$$..$$`, or `\[..\]`)
+;; can be enabled by setting `markdown-enable-math' to a non-nil value,
+;; either via customize or by placing `(setq markdown-enable-math t)`
+;; in `.emacs`, and then restarting Emacs or calling
+;; `markdown-reload-extensions'.
+
+;;; GitHub Flavored Markdown (GFM):
+
+;; A [GitHub Flavored Markdown][GFM] mode, `gfm-mode', is also
+;; available.  The GitHub implementation differs slightly from
+;; standard Markdown in that it supports things like different
+;; behavior for underscores inside of words, automatic linking of
+;; URLs, strikethrough text, and fenced code blocks with an optional
+;; language keyword.
+;;
+;; The GFM-specific features above apply to `README.md` files, wiki
+;; pages, and other Markdown-formatted files in repositories on
+;; GitHub.  GitHub also enables [additional features][GFM comments] for
+;; writing on the site (for issues, pull requests, messages, etc.)
+;; that are further extensions of GFM.  These features include task
+;; lists (checkboxes), newlines corresponding to hard line breaks,
+;; auto-linked references to issues and commits, wiki links, and so
+;; on.  To make matters more confusing, although task lists are not
+;; part of [GFM proper][GFM], [since 2014][] they are rendered (in a
+;; read-only fashion) in all Markdown documents in repositories on the
+;; site.  These additional extensions are supported to varying degrees
+;; by `markdown-mode' and `gfm-mode' as described below.
+;;
+;; * **URL autolinking:** Both `markdown-mode' and `gfm-mode' support
+;;   highlighting of URLs without angle brackets.
+;;
+;; * **Multiple underscores in words:** You must enable `gfm-mode' to
+;;   toggle support for underscores inside of words. In this mode
+;;   variable names such as `a_test_variable` will not trigger
+;;   emphasis (italics).
+;;
+;; * **Fenced code blocks:** Code blocks quoted with backticks, with
+;;   optional programming language keywords, are highlighted in
+;;   both `markdown-mode' and `gfm-mode'.  They can be inserted with
+;;   `C-c C-s P`.  If there is an active region, the text in the
+;;   region will be placed inside the code block.  You will be
+;;   prompted for the name of the language, but may press enter to
+;;   continue without naming a language.
+;;
+;; * **Strikethrough:** Strikethrough text is only supported in
+;;   `gfm-mode' and can be inserted (and toggled) using `C-c C-s d`.
+;;   Following the mnemonics for the other style keybindings, the
+;;   letter `d` coincides with the HTML tag `<del>`.
+;;
+;; * **Task lists:** GFM task lists will be rendered as checkboxes
+;;   (Emacs buttons) in both `markdown-mode' and `gfm-mode' when
+;;   `markdown-make-gfm-checkboxes-buttons' is set to a non-nil value
+;;   (and it is set to t by default).  These checkboxes can be
+;;   toggled by clicking `mouse-1` or pressing `RET` over the button.
+;;
+;; * **Wiki links:** Generic wiki links are supported in
+;;   `markdown-mode', but in `gfm-mode' specifically they will be
+;;   treated as they are on GitHub: spaces will be replaced by hyphens
+;;   in filenames and the first letter of the filename will be
+;;   capitalized.  For example, `[[wiki link]]' will map to a file
+;;   named `Wiki-link` with the same extension as the current file.
+;;
+;; * **Newlines:** Neither `markdown-mode' nor `gfm-mode' do anything
+;;   specifically with respect to newline behavior.  If you use
+;;   `gfm-mode' mostly to write text for comments or issues on the
+;;   GitHub site--where newlines are significant and correspond to
+;;   hard line breaks--then you may want to enable `visual-line-mode'
+;;   for line wrapping in buffers.  You can do this with a
+;;   `gfm-mode-hook' as follows:
+;;
+;;         ;; Use visual-line-mode in gfm-mode
+;;         (defun my-gfm-mode-hook ()
+;;           (visual-line-mode 1))
+;;         (add-hook 'gfm-mode-hook 'my-gfm-mode-hook)
+;;
+;; * **Preview:** GFM-specific preview can be powered by setting
+;;   `markdown-command' to use [Docter][].  This may also be
+;;   configured to work with [Marked 2][] for `markdown-open-command'.
+;;
+;; [GFM]: http://github.github.com/github-flavored-markdown/
+;; [GFM comments]: https://help.github.com/articles/writing-on-github/
+;; [since 2014]: https://github.com/blog/1825-task-lists-in-all-markdown-documents
+;; [Docter]: https://github.com/alampros/Docter
+
+;;; Acknowledgments:
+
+;; markdown-mode has benefited greatly from the efforts of the
+;; following people:
+;;
+;;   * Cyril Brulebois <cyril.brulebois@enst-bretagne.fr> for Debian packaging.
+;;   * Conal Elliott <conal@conal.net> for a font-lock regexp patch.
+;;   * Edward O'Connor <hober0@gmail.com> for a font-lock regexp fix and
+;;     GitHub Flavored Markdown mode (`gfm-mode').
+;;   * Greg Bognar <greg_bognar@hms.harvard.edu> for menus and running
+;;     `markdown' with an active region.
+;;   * Daniel Burrows <dburrows@debian.org> for filing Debian bug #456592.
+;;   * Peter S. Galbraith <psg@debian.org> for maintaining `emacs-goodies-el`.
+;;   * Dmitry Dzhus <mail@sphinx.net.ru> for undefined reference checking.
+;;   * Carsten Dominik <carsten@orgmode.org> for `org-mode', from which the
+;;     visibility cycling functionality was derived, and for a bug fix
+;;     related to `orgtbl-mode'.
+;;   * Bryan Kyle <bryan.kyle@gmail.com> for indentation code.
+;;   * Ben Voui <intrigeri@boum.org> for font-lock face customizations.
+;;   * Ankit Solanki <ankit.solanki@gmail.com> for `longlines.el`
+;;     compatibility and custom CSS.
+;;   * Hilko Bengen <bengen@debian.org> for proper XHTML output.
+;;   * Jose A. Ortega Ruiz <jao@gnu.org> for Emacs 23 fixes.
+;;   * Nelson Minar <nelson@santafe.edu> for `html-helper-mode', from which
+;;     comment matching functions were derived.
+;;   * Alec Resnick <alec@sproutward.org> for bug reports.
+;;   * Joost Kremers <joostkremers@fastmail.fm> for footnote-handling
+;;     functions, bug reports regarding indentation, and
+;;     fixes for byte-compilation warnings.
+;;   * Peter Williams <pezra@barelyenough.org> for `fill-paragraph'
+;;     enhancements.
+;;   * George Ogata <george.ogata@gmail.com> for fixing several
+;;     byte-compilation warnings.
+;;   * Eric Merritt <ericbmerritt@gmail.com> for wiki link features.
+;;   * Philippe Ivaldi <pivaldi@sfr.fr> for XHTML preview
+;;     customizations and XHTML export.
+;;   * Jeremiah Dodds <jeremiah.dodds@gmail.com> for supporting
+;;     Markdown processors which do not accept input from stdin.
+;;   * Werner Dittmann <werner.dittmann@t-online.de> for bug reports
+;;     regarding the `cl` dependency and `auto-fill-mode' and indentation.
+;;   * Scott Pfister <scott.pfister@gmail.com> for generalizing the space
+;;     substitution character for mapping wiki links to filenames.
+;;   * Marcin Kasperski <marcin.kasperski@mekk.waw.pl> for a patch to
+;;     escape shell commands.
+;;   * Christopher J. Madsen <cjm@cjmweb.net> for patches to fix a match
+;;     data bug and to prefer `visual-line-mode' in `gfm-mode'.
+;;   * Shigeru Fukaya <shigeru.fukaya@gmail.com> for better adherence to
+;;     Emacs Lisp coding conventions.
+;;   * Donald Ephraim Curtis <dcurtis@milkbox.net> for fixing the `fill-paragraph'
+;;     regexp, refactoring the compilation and preview functions,
+;;     heading font-lock generalizations, list renumbering,
+;;     and kill ring save.
+;;   * Kevin Porter <kportertx@gmail.com> for wiki link handling in `gfm-mode'.
+;;   * Max Penet <max.penet@gmail.com> and Peter Eisentraut <peter_e@gmx.net>
+;;     for an autoload token for `gfm-mode'.
+;;   * Ian Yang <me@iany.me> for improving the reference definition regex.
+;;   * Akinori Musha <knu@idaemons.org> for an imenu index function.
+;;   * Michael Sperber <sperber@deinprogramm.de> for XEmacs fixes.
+;;   * Francois Gannaz <francois.gannaz@free.fr> for suggesting charset
+;;     declaration in XHTML output.
+;;   * Zhenlei Jia <zhenlei.jia@gmail.com> for smart exdention function.
+;;   * Matus Goljer <dota.keys@gmail.com> for improved wiki link following
+;;     and GFM code block insertion.
+;;   * Peter Jones <pjones@pmade.com> for link following functions.
+;;   * Bryan Fink <bryan.fink@gmail.com> for a bug report regarding
+;;     externally modified files.
+;;   * Vegard Vesterheim <vegard.vesterheim@uninett.no> for a bug fix
+;;     related to `orgtbl-mode'.
+;;   * Makoto Motohashi <mkt.motohashi@gmail.com> for before- and after-
+;;     export hooks, unit test improvements, and updates to support
+;;     wide characters.
+;;   * Michael Dwyer <mdwyer@ehtech.in> for `gfm-mode' underscore regexp.
+;;   * Chris Lott <chris@chrislott.org> for suggesting reference label
+;;     completion.
+;;   * Gunnar Franke <Gunnar.Franke@gmx.de> for a completion bug report.
+;;   * David Glasser <glasser@meteor.com> for a `paragraph-separate' fix.
+;;   * Daniel Brotsky <dev@brotsky.com> for better auto-fill defaults.
+;;   * Samuel Freilich <sfreilich@google.com> for improved filling
+;;     behavior regarding list items, footnotes, and reference
+;;     definitions, improved killing of footnotes, and numerous other
+;;     tests and bug fixes.
+;;   * Antonis Kanouras <antonis@metadosis.gr> for strikethrough support.
+;;   * Tim Visher <tim.visher@gmail.com> for multiple CSS files and other
+;;     general improvements.
+;;   * Matt McClure <matthewlmcclure@gmail.com> for a patch to prevent
+;;     overwriting source files with .html extensions upon export.
+;;   * Roger Bolsius <roger.bolsius@gmail.com> for ordered list improvements.
+;;   * Google's Open Source Programs Office for recognizing the project with
+;;     a monetary contribution in June 2015.
+;;   * Howard Melman <hmelman@gmail.com> for supporting GFM checkboxes
+;;     as buttons.
+;;   * Danny McClanahan <danieldmcclanahan@gmail.com> for live preview mode,
+;;     completion of GFM programming language names, and `cl-lib' updates.
+;;   * Syohei Yoshida <syohex@gmail.com> for better heading detection
+;;     and movement functions.
+
+;;; Bugs:
+
+;; markdown-mode is developed and tested primarily for compatibility
+;; with GNU Emacs 24.3 and later.  If you find any bugs in
+;; markdown-mode, please construct a test case or a patch and open a
+;; ticket on the [GitHub issue tracker][issues].
+;;
+;;  [issues]: https://github.com/jrblevin/markdown-mode/issues
+
+;;; History:
+
+;; markdown-mode was written and is maintained by Jason Blevins.  The
+;; first version was released on May 24, 2007.
+;;
+;;   * 2007-05-24: Version 1.1
+;;   * 2007-05-25: Version 1.2
+;;   * 2007-06-05: [Version 1.3][]
+;;   * 2007-06-29: Version 1.4
+;;   * 2007-10-11: [Version 1.5][]
+;;   * 2008-06-04: [Version 1.6][]
+;;   * 2009-10-01: [Version 1.7][]
+;;   * 2011-08-12: [Version 1.8][]
+;;   * 2011-08-15: [Version 1.8.1][]
+;;   * 2013-01-25: [Version 1.9][]
+;;   * 2013-03-24: [Version 2.0][]
+;;   * 2016-01-09: [Version 2.1][]
+;;
+;; [Version 1.3]: http://jblevins.org/projects/markdown-mode/rev-1-3
+;; [Version 1.5]: http://jblevins.org/projects/markdown-mode/rev-1-5
+;; [Version 1.6]: http://jblevins.org/projects/markdown-mode/rev-1-6
+;; [Version 1.7]: http://jblevins.org/projects/markdown-mode/rev-1-7
+;; [Version 1.8]: http://jblevins.org/projects/markdown-mode/rev-1-8
+;; [Version 1.8.1]: http://jblevins.org/projects/markdown-mode/rev-1-8-1
+;; [Version 1.9]: http://jblevins.org/projects/markdown-mode/rev-1-9
+;; [Version 2.0]: http://jblevins.org/projects/markdown-mode/rev-2-0
+;; [Version 2.1]: http://jblevins.org/projects/markdown-mode/rev-2-1
+
+
+;;; Code:
+
+(require 'easymenu)
+(require 'outline)
+(require 'thingatpt)
+(require 'cl-lib)
+
+(declare-function eww-open-file "eww")
+
+
+;;; Constants =================================================================
+
+(defconst markdown-mode-version "2.1"
+  "Markdown mode version number.")
+
+(defconst markdown-output-buffer-name "*markdown-output*"
+  "Name of temporary buffer for markdown command output.")
+
+
+;;; Global Variables ==========================================================
+
+(defvar markdown-reference-label-history nil
+  "History of used reference labels.")
+
+(defvar markdown-live-preview-mode nil
+  "Sentinel variable for `markdown-live-preview-mode'.")
+
+(defvar markdown-gfm-language-history nil
+  "History list of languages used in the current buffer in GFM code blocks.")
+
+
+;;; Customizable Variables ====================================================
+
+(defvar markdown-mode-hook nil
+  "Hook run when entering Markdown mode.")
+
+(defvar markdown-before-export-hook nil
+  "Hook run before running Markdown to export XHTML output.
+The hook may modify the buffer, which will be restored to it's
+original state after exporting is complete.")
+
+(defvar markdown-after-export-hook nil
+  "Hook run after XHTML output has been saved.
+Any changes to the output buffer made by this hook will be saved.")
+
+(defgroup markdown nil
+  "Major mode for editing text files in Markdown format."
+  :prefix "markdown-"
+  :group 'wp
+  :link '(url-link "http://jblevins.org/projects/markdown-mode/"))
+
+(defcustom markdown-command "markdown"
+  "Command to run markdown."
+  :group 'markdown
+  :type 'string)
+
+(defcustom markdown-command-needs-filename nil
+  "Set to non-nil if `markdown-command' does not accept input from stdin.
+Instead, it will be passed a filename as the final command line
+option.  As a result, you will only be able to run Markdown from
+buffers which are visiting a file."
+  :group 'markdown
+  :type 'boolean)
+
+(defcustom markdown-open-command nil
+  "Command used for opening Markdown files directly.
+For example, a standalone Markdown previewer.  This command will
+be called with a single argument: the filename of the current
+buffer."
+  :group 'markdown
+  :type 'string)
+
+(defcustom markdown-hr-strings
+  '("-------------------------------------------------------------------------------"
+    "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *"
+    "---------------------------------------"
+    "* * * * * * * * * * * * * * * * * * * *"
+    "---------"
+    "* * * * *")
+  "Strings to use when inserting horizontal rules.
+The first string in the list will be the default when inserting a
+horizontal rule.  Strings should be listed in decreasing order of
+prominence (as in headings from level one to six) for use with
+promotion and demotion functions."
+  :group 'markdown
+  :type 'list)
+
+(defcustom markdown-bold-underscore nil
+  "Use two underscores for bold instead of two asterisks."
+  :group 'markdown
+  :type 'boolean)
+
+(defcustom markdown-italic-underscore nil
+  "Use underscores for italic instead of asterisks."
+  :group 'markdown
+  :type 'boolean)
+
+(defcustom markdown-asymmetric-header nil
+  "Determines if header style will be asymmetric.
+Set to non-nil to only have header characters to the left of the title.
+The default will ensure header characters are placed to the left and right
+of the title."
+  :group 'markdown
+  :type 'boolean)
+
+(defcustom markdown-indent-function 'markdown-indent-line
+  "Function to use to indent."
+  :group 'markdown
+  :type 'function)
+
+(defcustom markdown-indent-on-enter t
+  "Automatically indent new lines when enter key is pressed.
+When this variable is set to t, pressing RET will call
+`newline-and-indent'.  When set to nil, define RET to call
+`newline' as usual.  In the latter case, you can still use
+auto-indentation by pressing \\[newline-and-indent]."
+  :group 'markdown
+  :type 'boolean)
+
+(defcustom markdown-wiki-link-alias-first t
+  "When non-nil, treat aliased wiki links like [[alias text|PageName]].
+Otherwise, they will be treated as [[PageName|alias text]]."
+  :group 'markdown
+  :type 'boolean
+  :safe 'booleanp)
+
+(defcustom markdown-wiki-link-search-parent-directories nil
+  "When non-nil, search for wiki link targets in parent directories.
+This is the default search behavior of Ikiwiki."
+  :group 'markdown
+  :type 'boolean
+  :safe 'booleanp)
+
+(defcustom markdown-uri-types
+  '("acap" "cid" "data" "dav" "fax" "file" "ftp" "gopher" "http" "https"
+    "imap" "ldap" "mailto" "mid" "modem" "news" "nfs" "nntp" "pop" "prospero"
+    "rtsp" "service" "sip" "tel" "telnet" "tip" "urn" "vemmi" "wais")
+  "Link types for syntax highlighting of URIs."
+  :group 'markdown
+  :type 'list)
+
+(defcustom markdown-enable-math nil
+  "Syntax highlighting for inline LaTeX and itex expressions.
+Set this to a non-nil value to turn on math support by default.
+Math support can be toggled later using `markdown-enable-math'
+or \\[markdown-enable-math]."
+  :group 'markdown
+  :type 'boolean
+  :safe 'booleanp)
+
+(defcustom markdown-css-paths nil
+  "URL of CSS file to link to in the output XHTML."
+  :group 'markdown
+  :type 'list)
+
+(defcustom markdown-content-type ""
+  "Content type string for the http-equiv header in XHTML output.
+When set to a non-empty string, insert the http-equiv attribute.
+Otherwise, this attribute is omitted."
+  :group 'markdown
+  :type 'string)
+
+(defcustom markdown-coding-system nil
+  "Character set string for the http-equiv header in XHTML output.
+Defaults to `buffer-file-coding-system' (and falling back to
+`iso-8859-1' when not available).  Common settings are `utf-8'
+and `iso-latin-1'.  Use `list-coding-systems' for more choices."
+  :group 'markdown
+  :type 'coding-system)
+
+(defcustom markdown-xhtml-header-content ""
+  "Additional content to include in the XHTML <head> block."
+  :group 'markdown
+  :type 'string)
+
+(defcustom markdown-xhtml-standalone-regexp
+  "^\\(<\\?xml\\|<!DOCTYPE\\|<html\\)"
+  "Regexp indicating whether `markdown-command' output is standalone XHTML."
+  :group 'markdown
+  :type 'regexp)
+
+(defcustom markdown-link-space-sub-char "_"
+  "Character to use instead of spaces when mapping wiki links to filenames."
+  :group 'markdown
+  :type 'string)
+
+(defcustom markdown-reference-location 'header
+  "Position where new reference definitions are inserted in the document."
+  :group 'markdown
+  :type '(choice (const :tag "At the end of the document" end)
+                 (const :tag "Immediately after the current block" immediately)
+                 (const :tag "Before next header" header)))
+
+(defcustom markdown-footnote-location 'end
+  "Position where new footnotes are inserted in the document."
+  :group 'markdown
+  :type '(choice (const :tag "At the end of the document" end)
+                 (const :tag "Immediately after the current block" immediately)
+                 (const :tag "Before next header" header)))
+
+(defcustom markdown-unordered-list-item-prefix "  * "
+  "String inserted before unordered list items."
+  :group 'markdown
+  :type 'string)
+
+(defcustom markdown-make-gfm-checkboxes-buttons t
+  "When non-nil, make GFM checkboxes into buttons."
+  :group 'markdown
+  :type 'boolean)
+
+(defcustom markdown-live-preview-window-function
+  'markdown-live-preview-window-eww
+  "Function to display preview of Markdown output within Emacs. Function must
+update the buffer containing the preview and return the buffer."
+  :group 'markdown
+  :type 'function)
+
+(defcustom markdown-live-preview-delete-export 'delete-on-destroy
+  "Delete exported html file when using `markdown-live-preview-export' on every
+export by setting to 'delete-on-export, when quitting
+`markdown-live-preview-mode' by setting to 'delete-on-destroy, or not at all
+when nil."
+  :group 'markdown
+  :type 'symbol)
+
+(defcustom markdown-list-indent-width 4
+  "Depth of indentation for markdown lists. Used in `markdown-demote-list-item'
+and `markdown-promote-list-item'."
+  :group 'markdown
+  :type 'integer)
+
+(defcustom markdown-gfm-additional-languages nil
+  "Additional languages to make available when inserting GFM code
+blocks. Language strings must have be trimmed of whitespace and not contain any
+curly braces. They may be of arbitrary capitalization, though."
+  :group 'markdown
+  :type '(repeat (string :validate markdown-validate-language-string)))
+
+(defcustom markdown-gfm-use-electric-backquote t
+  "Use `markdown-electric-backquote' when backquote is hit three times."
+  :group 'markdown
+  :type 'boolean)
+
+
+;;; Regular Expressions =======================================================
+
+(defconst markdown-regex-comment-start
+  "<!--"
+  "Regular expression matches HTML comment opening.")
+
+(defconst markdown-regex-comment-end
+  "--[ \t]*>"
+  "Regular expression matches HTML comment closing.")
+
+(defconst markdown-regex-link-inline
+  "\\(!\\)?\\(\\[\\)\\([^]^][^]]*\\|\\)\\(\\]\\)\\((\\)\\([^)]*?\\)\\(?:\\s-+\\(\"[^\"]*\"\\)\\)?\\()\\)"
+  "Regular expression for a [text](file) or an image link ![text](file).
+Group 1 matches the leading exclamation point (optional).
+Group 2 matches the opening square bracket.
+Group 3 matches the text inside the square brackets.
+Group 4 matches the closing square bracket.
+Group 5 matches the opening parenthesis.
+Group 6 matches the URL.
+Group 7 matches the title (optional).
+Group 8 matches the closing parenthesis.")
+
+(defconst markdown-regex-link-reference
+  "\\(!\\)?\\(\\[\\)\\([^]^][^]]*\\|\\)\\(\\]\\)[ ]?\\(\\[\\)\\([^]]*?\\)\\(\\]\\)"
+  "Regular expression for a reference link [text][id].
+Group 1 matches the leading exclamation point (optional).
+Group 2 matches the opening square bracket for the link text.
+Group 3 matches the text inside the square brackets.
+Group 4 matches the closing square bracket for the link text.
+Group 5 matches the opening square bracket for the reference label.
+Group 6 matches the reference label.
+Group 7 matches the closing square bracket for the reference label.")
+
+(defconst markdown-regex-reference-definition
+  "^ \\{0,3\\}\\(\\[\\)\\([^]\n]+?\\)\\(\\]\\)\\(:\\)\\s *\\(.*?\\)\\s *\\( \"[^\"]*\"$\\|$\\)"
+  "Regular expression for a reference definition.
+Group 1 matches the opening square bracket.
+Group 2 matches the reference label.
+Group 3 matches the closing square bracket.
+Group 4 matches the colon.
+Group 5 matches the URL.
+Group 6 matches the title attribute (optional).")
+
+(defconst markdown-regex-footnote
+  "\\(\\[\\^\\)\\(.+?\\)\\(\\]\\)"
+  "Regular expression for a footnote marker [^fn].
+Group 1 matches the opening square bracket and carat.
+Group 2 matches only the label, without the surrounding markup.
+Group 3 matches the closing square bracket.")
+
+(defconst markdown-regex-header
+  "^\\(?:\\(.+\\)\n\\(=+\\)\\|\\(.+\\)\n\\(-+\\)\\|\\(#+\\)\\s-*\\(.*?\\)\\s-*?\\(#*\\)\\)$"
+  "Regexp identifying Markdown headers.")
+
+(defconst markdown-regex-header-1-atx
+  "^\\(#\\)[ \t]*\\([^\\.].*?\\)[ \t]*\\(#*\\)$"
+  "Regular expression for level 1 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-2-atx
+  "^\\(##\\)[ \t]*\\(.+?\\)[ \t]*\\(#*\\)$"
+  "Regular expression for level 2 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-3-atx
+  "^\\(###\\)[ \t]*\\(.+?\\)[ \t]*\\(#*\\)$"
+  "Regular expression for level 3 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-4-atx
+  "^\\(####\\)[ \t]*\\(.+?\\)[ \t]*\\(#*\\)$"
+  "Regular expression for level 4 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-5-atx
+  "^\\(#####\\)[ \t]*\\(.+?\\)[ \t]*\\(#*\\)$"
+  "Regular expression for level 5 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-6-atx
+  "^\\(######\\)[ \t]*\\(.+?\\)[ \t]*\\(#*\\)$"
+  "Regular expression for level 6 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-1-setext
+  "^\\(.*\\)\n\\(=+\\)$"
+  "Regular expression for level 1 setext-style (underline) headers.")
+
+(defconst markdown-regex-header-2-setext
+  "^\\(.*\\)\n\\(-+\\)$"
+  "Regular expression for level 2 setext-style (underline) headers.")
+
+(defconst markdown-regex-header-setext
+  "^\\(.+\\)\n\\(\\(?:=\\|-\\)+\\)$"
+  "Regular expression for generic setext-style (underline) headers.")
+
+(defconst markdown-regex-header-atx
+  "^\\(#+\\)[ \t]*\\(.*?\\)[ \t]*\\(#*\\)$"
+  "Regular expression for generic atx-style (hash mark) headers.")
+
+(defconst markdown-regex-hr
+  "^\\(\\*[ ]?\\*[ ]?\\*[ ]?[\\* ]*\\|-[ ]?-[ ]?-[--- ]*\\)$"
+  "Regular expression for matching Markdown horizontal rules.")
+
+(defconst markdown-regex-code
+  "\\(?:\\`\\|[^\\]\\)\\(\\(`+\\)\\(\\(?:.\\|\n[^\n]\\)*?[^`]\\)\\(\\2\\)\\)\\(?:[^`]\\|\\'\\)"
+  "Regular expression for matching inline code fragments.
+
+Group 1 matches the entire code fragment including the backticks.
+Group 2 matches the opening backticks.
+Group 3 matches the code fragment itself, without backticks.
+Group 4 matches the closing backticks.
+
+The leading, unnumbered group ensures that the leading backquote
+character is not escaped.
+The last group, also unnumbered, requires that the character
+following the code fragment is not a backquote.
+Note that \\(?:.\\|\n[^\n]\\) matches any character, including newlines,
+but not two newlines in a row.")
+
+(defconst markdown-regex-kbd
+  "\\(<kbd>\\)\\(\\(?:.\\|\n[^\n]\\)*?\\)\\(</kbd>\\)"
+  "Regular expression for matching <kbd> tags.
+Groups 1 and 3 match the opening and closing tags.
+Group 2 matches the key sequence.")
+
+(defconst markdown-regex-gfm-code-block
+  (concat
+   "^\\s *\\(```\\)[ ]*\\([^[:space:]]+\\|{[^}]*}\\)?"
+   "[[:space:]]*?\n"
+   "\\(\\(?:.\\|\n\\)*?\\)?"
+   "\n?\\s *?\\(```\\)\\s *?$")
+ "Regular expression matching opening of GFM code blocks.
+Group 1 matches the opening three backticks.
+Group 2 matches the language identifier (optional).
+Group 3 matches the closing three backticks.")
+
+(defconst markdown-regex-pre
+  "^\\(    \\|\t\\).*$"
+  "Regular expression for matching preformatted text sections.")
+
+(defconst markdown-regex-list
+  "^\\([ \t]*\\)\\([0-9#]+\\.\\|[\\*\\+-]\\)\\([ \t]+\\)"
+  "Regular expression for matching list items.")
+
+(defconst markdown-regex-bold
+  "\\(^\\|[^\\]\\)\\(\\([*_]\\{2\\}\\)\\([^ \n\t\\]\\|[^ \n\t]\\(?:.\\|\n[^\n]\\)*?[^\\ ]\\)\\(\\3\\)\\)"
+  "Regular expression for matching bold text.
+Group 1 matches the character before the opening asterisk or
+underscore, if any, ensuring that it is not a backslash escape.
+Group 2 matches the entire expression, including delimiters.
+Groups 3 and 5 matches the opening and closing delimiters.
+Group 4 matches the text inside the delimiters.")
+
+(defconst markdown-regex-italic
+  "\\(?:^\\|[^\\]\\)\\(\\([*_]\\)\\([^ \n\t\\]\\|[^ \n\t]\\(?:.\\|\n[^\n]\\)*?[^\\ ]\\)\\(\\2\\)\\)"
+  "Regular expression for matching italic text.
+The leading unnumbered matches the character before the opening
+asterisk or underscore, if any, ensuring that it is not a
+backslash escape.
+Group 1 matches the entire expression, including delimiters.
+Groups 2 and 4 matches the opening and closing delimiters.
+Group 3 matches the text inside the delimiters.")
+
+(defconst markdown-regex-strike-through
+  "\\(^\\|[^\\]\\)\\(\\(~~\\)\\([^ \n\t\\]\\|[^ \n\t]\\(?:.\\|\n[^\n]\\)*?[^\\ ]\\)\\(~~\\)\\)"
+  "Regular expression for matching strike-through text.
+Group 1 matches the character before the opening tilde, if any,
+ensuring that it is not a backslash escape.
+Group 2 matches the entire expression, including delimiters.
+Groups 3 and 5 matches the opening and closing delimiters.
+Group 4 matches the text inside the delimiters.")
+
+(defconst markdown-regex-gfm-italic
+  "\\(?:^\\|\\s-\\)\\(\\([*_]\\)\\([^ \\]\\2\\|[^ ]\\(?:.\\|\n[^\n]\\)*?[^\\ ]\\)\\(\\2\\)\\)"
+  "Regular expression for matching italic text in GitHub Flavored Markdown.
+Underscores in words are not treated as special.
+Group 1 matches the entire expression, including delimiters.
+Groups 2 and 4 matches the opening and closing delimiters.
+Group 3 matches the text inside the delimiters.")
+
+(defconst markdown-regex-blockquote
+  "^[ \t]*\\(>\\)\\(.*\\)$"
+  "Regular expression for matching blockquote lines.
+Group 1 matches the leading angle bracket.
+Group 2 matches the text.")
+
+(defconst markdown-regex-line-break
+  "[^ \n\t][ \t]*\\(  \\)$"
+  "Regular expression for matching line breaks.")
+
+(defconst markdown-regex-wiki-link
+  "\\(?:^\\|[^\\]\\)\\(\\(\\[\\[\\)\\([^]|]+\\)\\(?:\\(|\\)\\([^]]+\\)\\)?\\(\\]\\]\\)\\)"
+  "Regular expression for matching wiki links.
+This matches typical bracketed [[WikiLinks]] as well as 'aliased'
+wiki links of the form [[PageName|link text]].
+The meanings of the first and second components depend
+on the value of `markdown-wiki-link-alias-first'.
+
+Group 1 matches the entire link.
+Group 2 matches the opening square brackets.
+Group 3 matches the first component of the wiki link.
+Group 4 matches the pipe separator, when present.
+Group 5 matches the second component of the wiki link, when present.
+Group 6 matches the closing square brackets.")
+
+(defconst markdown-regex-uri
+  (concat (regexp-opt markdown-uri-types) ":[^]\t\n\r<>,;() ]+")
+  "Regular expression for matching inline URIs.")
+
+(defconst markdown-regex-angle-uri
+  (concat "\\(<\\)\\(" (regexp-opt markdown-uri-types) ":[^]\t\n\r<>,;()]+\\)\\(>\\)")
+  "Regular expression for matching inline URIs in angle brackets.")
+
+(defconst markdown-regex-email
+  "<\\(\\(\\sw\\|\\s_\\|\\s.\\)+@\\(\\sw\\|\\s_\\|\\s.\\)+\\)>"
+  "Regular expression for matching inline email addresses.")
+
+(defconst markdown-regex-link-generic
+  (concat "\\(?:" markdown-regex-wiki-link
+          "\\|" markdown-regex-link-inline
+          "\\|" markdown-regex-link-reference
+          "\\|" markdown-regex-angle-uri "\\)")
+  "Regular expression for matching any recognized link.")
+
+(defconst markdown-regex-gfm-checkbox
+  " \\(\\[[ xX]\\]\\) "
+  "Regular expression for matching GFM checkboxes.
+Group 1 matches the text to become a button.")
+
+(defconst markdown-regex-block-separator
+  "\\(\\`\\|\\(\n[ \t]*\n\\)[^\n \t]\\)"
+  "Regular expression for matching block boundaries.")
+
+(defconst markdown-regex-math-inline-single
+  "\\(?:^\\|[^\\]\\)\\(\\$\\)\\(\\(?:[^\\$]\\|\\\\.\\)*\\)\\(\\$\\)"
+  "Regular expression for itex $..$ math mode expressions.
+Groups 1 and 3 match the opening and closing dollar signs.
+Group 3 matches the mathematical expression contained within.")
+
+(defconst markdown-regex-math-inline-double
+  "\\(?:^\\|[^\\]\\)\\(\\$\\$\\)\\(\\(?:[^\\$]\\|\\\\.\\)*\\)\\(\\$\\$\\)"
+  "Regular expression for itex $$..$$ math mode expressions.
+Groups 1 and 3 match opening and closing dollar signs.
+Group 3 matches the mathematical expression contained within.")
+
+(defconst markdown-regex-math-display
+  "^\\(\\\\\\[\\)\\(\\(?:.\\|\n\\)*\\)?\\(\\\\\\]\\)$"
+  "Regular expression for itex \[..\] display mode expressions.
+Groups 1 and 3 matche the opening and closing delimiters.
+Group 2 matches the mathematical expression contained within.")
+
+(defconst markdown-regex-multimarkdown-metadata
+  "^\\([[:alpha:]][[:alpha:] _-]*?\\)\\(:[ \t]*\\)\\(.*\\)$"
+  "Regular expression for matching MultiMarkdown metadata.")
+
+(defconst markdown-regex-pandoc-metadata
+  "^\\(%\\)\\([ \t]*\\)\\(.*\\)$"
+  "Regular expression for matching Pandoc metadata.")
+
+
+;;; Syntax ====================================================================
+
+(defun markdown-syntax-propertize-extend-region (start end)
+  "Extend START to END region to include an entire block of text.
+This helps improve syntax analysis for block constructs.
+Returns a cons (NEW-START . NEW-END) or nil if no adjustment should be made.
+Function is called repeatedly until it returns nil. For details, see
+`syntax-propertize-extend-region-functions'."
+  (save-excursion
+    (goto-char start)
+    (unless (or (bobp) (looking-back "\n\n" nil))
+      (let (new-start new-end)
+        (setq new-start (if (re-search-backward "\n\n" nil t)
+                            (match-end 0)
+                          (point-min)))
+        (goto-char end)
+        (setq new-end (if (re-search-forward "\n\n" nil t)
+                          (match-beginning 0)
+                        (point-max)))
+        (unless (and (eq new-start start) (eq new-end end))
+          (cons new-start new-end))))))
+
+(defun markdown-syntax-propertize-pre-blocks (start end)
+  "Match preformatted text blocks from START to END."
+  (save-excursion
+    (goto-char start)
+    (let ((levels (markdown-calculate-list-levels))
+          indent pre-regexp close-regexp open close stop)
+      (while (and (< (point) end) (not close))
+        ;; Search for a region with sufficient indentation
+        (if (null levels)
+            (setq indent 1)
+          (setq indent (1+ (length levels))))
+        (setq pre-regexp (format "^\\(    \\|\t\\)\\{%d\\}" indent))
+        (setq close-regexp (format "^\\(    \\|\t\\)\\{0,%d\\}\\([^ \t]\\)" (1- indent)))
+
+        (cond
+         ;; If not at the beginning of a line, move forward
+         ((not (bolp)) (forward-line))
+         ;; Move past blank lines
+         ((markdown-cur-line-blank-p) (forward-line))
+         ;; At headers and horizontal rules, reset levels
+         ((markdown-new-baseline-p) (forward-line) (setq levels nil))
+         ;; If the current line has sufficient indentation, mark out pre block
+         ;; The opening should be preceded by a blank line.
+         ((and (looking-at pre-regexp)
+               (markdown-prev-line-blank-p))
+          (setq open (match-beginning 0))
+          (while (and (or (looking-at pre-regexp) (markdown-cur-line-blank-p))
+                      (not (eobp)))
+            (forward-line))
+          (skip-syntax-backward "-")
+          (setq close (point)))
+         ;; If current line has a list marker, update levels, move to end of block
+         ((looking-at markdown-regex-list)
+          (setq levels (markdown-update-list-levels
+                        (match-string 2) (markdown-cur-line-indent) levels))
+          (markdown-end-of-block-element))
+         ;; If this is the end of the indentation level, adjust levels accordingly.
+         ;; Only match end of indentation level if levels is not the empty list.
+         ((and (car levels) (looking-at close-regexp))
+          (setq levels (markdown-update-list-levels
+                        nil (markdown-cur-line-indent) levels))
+          (markdown-end-of-block-element))
+         (t (markdown-end-of-block-element))))
+
+      (when (and open close)
+        ;; Set text property data
+        (put-text-property open close 'markdown-pre (list open close))
+        ;; Recursively search again
+        (markdown-syntax-propertize-pre-blocks (point) end)))))
+
+(defun markdown-syntax-propertize-fenced-code-blocks (start end)
+  "Match tilde-fenced code text blocks from START to END."
+  (save-excursion
+    (goto-char start)
+    (while (re-search-forward "^\\([~]\\{3,\\}\\)" end t)
+      (let ((beg (match-beginning 1)))
+        (when (re-search-forward
+               (concat "^" (match-string 1) "~*") end t)
+          (put-text-property beg (match-end 0) 'markdown-fenced-code
+                             (list beg (point))))))))
+
+(defun markdown-syntax-propertize-gfm-code-blocks (start end)
+  "Match GFM code blocks from START to END."
+  (save-excursion
+    (goto-char start)
+    (while (re-search-forward markdown-regex-gfm-code-block end t)
+      (let ((open (list (match-beginning 1) (match-end 1)))
+            (lang (list (match-beginning 2) (match-end 2)))
+            (body (list (match-beginning 3) (match-end 3)))
+            (close (list (match-beginning 4) (match-end 4)))
+            (all (list (match-beginning 1) (match-end 4))))
+        (put-text-property (cl-first open) (cl-second close) 'markdown-gfm-code
+                           (append all open lang body close))))))
+
+(defun markdown-syntax-propertize-blockquotes (start end)
+  "Match blockquotes from START to END."
+  (save-excursion
+    (goto-char start)
+    (while (and (re-search-forward markdown-regex-blockquote end t)
+                (not (markdown-code-block-at-pos (match-beginning 0))))
+      (put-text-property (match-beginning 0) (match-end 0)
+                         'markdown-blockquote
+                         (match-data t)))))
+
+(defun markdown-syntax-propertize-headings-generic (symbol regex start end)
+  "Match headings of type SYMBOL with REGEX from START to END."
+  (save-excursion
+    (goto-char start)
+    (while (re-search-forward regex end t)
+      (unless (or (markdown-code-block-at-pos (match-beginning 0))
+                  (get-text-property (match-beginning 0) 'markdown-heading))
+        (put-text-property (match-beginning 0) (match-end 0)
+                           'markdown-heading t)
+        (put-text-property (match-beginning 0) (match-end 0)
+                           symbol (match-data t))))))
+
+(defun markdown-syntax-propertize-comments (start end)
+  "Match HTML comments from the START to END."
+  (let* ((state (syntax-ppss)) (in-comment (nth 4 state)))
+    (goto-char start)
+    (cond
+     ;; Comment start
+     ((and (not in-comment)
+           (re-search-forward markdown-regex-comment-start end t)
+           (save-match-data (not (markdown-code-at-point-p)))
+           (save-match-data (not (markdown-code-block-at-point))))
+      (let ((open-beg (match-beginning 0)))
+        (put-text-property open-beg (1+ open-beg)
+                           'syntax-table (string-to-syntax "<"))
+        (markdown-syntax-propertize-comments (1+ open-beg) end)))
+     ;; Comment end
+     ((and in-comment
+           (re-search-forward markdown-regex-comment-end end t))
+      (put-text-property (1- (match-end 0)) (match-end 0)
+                         'syntax-table (string-to-syntax ">"))
+      (markdown-syntax-propertize-comments (match-end 0) end))
+     ;; Nothing found
+     (t nil))))
+
+(defun markdown-syntax-propertize (start end)
+  "See `syntax-propertize-function'."
+  (remove-text-properties start end '(markdown-gfm-code))
+  (remove-text-properties start end '(markdown-fenced-code))
+  (remove-text-properties start end '(markdown-pre))
+  (remove-text-properties start end '(markdown-blockquote))
+  (remove-text-properties start end '(markdown-heading))
+  (remove-text-properties start end '(markdown-heading-1-setext))
+  (remove-text-properties start end '(markdown-heading-2-setext))
+  (remove-text-properties start end '(markdown-heading-1-atx))
+  (remove-text-properties start end '(markdown-heading-2-atx))
+  (remove-text-properties start end '(markdown-heading-3-atx))
+  (remove-text-properties start end '(markdown-heading-4-atx))
+  (remove-text-properties start end '(markdown-heading-5-atx))
+  (remove-text-properties start end '(markdown-heading-6-atx))
+  (markdown-syntax-propertize-gfm-code-blocks start end)
+  (markdown-syntax-propertize-fenced-code-blocks start end)
+  (markdown-syntax-propertize-pre-blocks start end)
+  (markdown-syntax-propertize-blockquotes start end)
+  (markdown-syntax-propertize-headings-generic
+   'markdown-heading-1-setext markdown-regex-header-1-setext start end)
+  (markdown-syntax-propertize-headings-generic
+   'markdown-heading-2-setext markdown-regex-header-2-setext start end)
+  (markdown-syntax-propertize-headings-generic
+   'markdown-heading-6-atx markdown-regex-header-6-atx start end)
+  (markdown-syntax-propertize-headings-generic
+   'markdown-heading-5-atx markdown-regex-header-5-atx start end)
+  (markdown-syntax-propertize-headings-generic
+   'markdown-heading-4-atx markdown-regex-header-4-atx start end)
+  (markdown-syntax-propertize-headings-generic
+   'markdown-heading-3-atx markdown-regex-header-3-atx start end)
+  (markdown-syntax-propertize-headings-generic
+   'markdown-heading-2-atx markdown-regex-header-2-atx start end)
+  (markdown-syntax-propertize-headings-generic
+   'markdown-heading-1-atx markdown-regex-header-1-atx start end)
+  (markdown-syntax-propertize-comments start end))
+
+
+;;; Font Lock =================================================================
+
+(require 'font-lock)
+
+(defvar markdown-italic-face 'markdown-italic-face
+  "Face name to use for italic text.")
+
+(defvar markdown-bold-face 'markdown-bold-face
+  "Face name to use for bold text.")
+
+(defvar markdown-strike-through-face 'markdown-strike-through-face
+  "Face name to use for strike-through text.")
+
+(defvar markdown-header-delimiter-face 'markdown-header-delimiter-face
+  "Face name to use as a base for header delimiters.")
+
+(defvar markdown-header-rule-face 'markdown-header-rule-face
+  "Face name to use as a base for header rules.")
+
+(defvar markdown-header-face 'markdown-header-face
+  "Face name to use as a base for headers.")
+
+(defvar markdown-header-face-1 'markdown-header-face-1
+  "Face name to use for level-1 headers.")
+
+(defvar markdown-header-face-2 'markdown-header-face-2
+  "Face name to use for level-2 headers.")
+
+(defvar markdown-header-face-3 'markdown-header-face-3
+  "Face name to use for level-3 headers.")
+
+(defvar markdown-header-face-4 'markdown-header-face-4
+  "Face name to use for level-4 headers.")
+
+(defvar markdown-header-face-5 'markdown-header-face-5
+  "Face name to use for level-5 headers.")
+
+(defvar markdown-header-face-6 'markdown-header-face-6
+  "Face name to use for level-6 headers.")
+
+(defvar markdown-inline-code-face 'markdown-inline-code-face
+  "Face name to use for inline code.")
+
+(defvar markdown-list-face 'markdown-list-face
+  "Face name to use for list markers.")
+
+(defvar markdown-blockquote-face 'markdown-blockquote-face
+  "Face name to use for blockquote.")
+
+(defvar markdown-pre-face 'markdown-pre-face
+  "Face name to use for preformatted text.")
+
+(defvar markdown-language-keyword-face 'markdown-language-keyword-face
+  "Face name to use for programming language identifiers.")
+
+(defvar markdown-link-face 'markdown-link-face
+  "Face name to use for links.")
+
+(defvar markdown-missing-link-face 'markdown-missing-link-face
+  "Face name to use for links where the linked file does not exist.")
+
+(defvar markdown-reference-face 'markdown-reference-face
+  "Face name to use for reference.")
+
+(defvar markdown-footnote-face 'markdown-footnote-face
+  "Face name to use for footnote identifiers.")
+
+(defvar markdown-url-face 'markdown-url-face
+  "Face name to use for URLs.")
+
+(defvar markdown-link-title-face 'markdown-link-title-face
+  "Face name to use for reference link titles.")
+
+(defvar markdown-line-break-face 'markdown-line-break-face
+  "Face name to use for hard line breaks.")
+
+(defvar markdown-comment-face 'markdown-comment-face
+  "Face name to use for HTML comments.")
+
+(defvar markdown-math-face 'markdown-math-face
+  "Face name to use for LaTeX expressions.")
+
+(defvar markdown-metadata-key-face 'markdown-metadata-key-face
+  "Face name to use for metadata keys.")
+
+(defvar markdown-metadata-value-face 'markdown-metadata-value-face
+  "Face name to use for metadata values.")
+
+(defvar markdown-gfm-checkbox-face 'markdown-gfm-checkbox-face
+  "Face name to use for GFM checkboxes.")
+
+(defvar markdown-highlight-face 'markdown-highlight-face
+  "Face name to use for mouse highlighting.")
+
+(defvar markdown-markup-face 'markdown-markup-face
+  "Face name to use for markup elements.")
+
+(defgroup markdown-faces nil
+  "Faces used in Markdown Mode"
+  :group 'markdown
+  :group 'faces)
+
+(defface markdown-italic-face
+  '((t (:inherit font-lock-variable-name-face :slant italic :weight normal)))
+  "Face for italic text."
+  :group 'markdown-faces)
+
+(defface markdown-bold-face
+  '((t (:inherit font-lock-variable-name-face :weight bold :slant normal)))
+  "Face for bold text."
+  :group 'markdown-faces)
+
+(defface markdown-strike-through-face
+  '((t (:inherit font-lock-variable-name-face :strike-through t)))
+  "Face for strike-through text."
+  :group 'markdown-faces)
+
+(defface markdown-markup-face
+  '((t (:inherit shadow :slant normal :weight normal)))
+  "Face for markup elements."
+  :group 'markdown-faces)
+
+(defface markdown-header-rule-face
+  '((t (:inherit markdown-markup-face)))
+  "Base face for headers rules."
+  :group 'markdown-faces)
+
+(defface markdown-header-delimiter-face
+  '((t (:inherit markdown-markup-face)))
+  "Base face for headers hash delimiter."
+  :group 'markdown-faces)
+
+(defface markdown-header-face
+  '((t (:inherit font-lock-function-name-face :weight bold)))
+  "Base face for headers."
+  :group 'markdown-faces)
+
+(defface markdown-header-face-1
+  '((t (:inherit markdown-header-face)))
+  "Face for level-1 headers."
+  :group 'markdown-faces)
+
+(defface markdown-header-face-2
+  '((t (:inherit markdown-header-face)))
+  "Face for level-2 headers."
+  :group 'markdown-faces)
+
+(defface markdown-header-face-3
+  '((t (:inherit markdown-header-face)))
+  "Face for level-3 headers."
+  :group 'markdown-faces)
+
+(defface markdown-header-face-4
+  '((t (:inherit markdown-header-face)))
+  "Face for level-4 headers."
+  :group 'markdown-faces)
+
+(defface markdown-header-face-5
+  '((t (:inherit markdown-header-face)))
+  "Face for level-5 headers."
+  :group 'markdown-faces)
+
+(defface markdown-header-face-6
+  '((t (:inherit markdown-header-face)))
+  "Face for level-6 headers."
+  :group 'markdown-faces)
+
+(defface markdown-inline-code-face
+  '((t (:inherit font-lock-constant-face)))
+  "Face for inline code."
+  :group 'markdown-faces)
+
+(defface markdown-list-face
+  '((t (:inherit markdown-markup-face)))
+  "Face for list item markers."
+  :group 'markdown-faces)
+
+(defface markdown-blockquote-face
+  '((t (:inherit font-lock-doc-face)))
+  "Face for blockquote sections."
+  :group 'markdown-faces)
+
+(defface markdown-pre-face
+  '((t (:inherit font-lock-constant-face)))
+  "Face for preformatted text."
+  :group 'markdown-faces)
+
+(defface markdown-language-keyword-face
+  '((t (:inherit font-lock-type-face)))
+  "Face for programming language identifiers."
+  :group 'markdown-faces)
+
+(defface markdown-link-face
+  '((t (:inherit font-lock-keyword-face)))
+  "Face for links."
+  :group 'markdown-faces)
+
+(defface markdown-missing-link-face
+  '((t (:inherit font-lock-warning-face)))
+  "Face for missing links."
+  :group 'markdown-faces)
+
+(defface markdown-reference-face
+  '((t (:inherit markdown-markup-face)))
+  "Face for link references."
+  :group 'markdown-faces)
+
+(defface markdown-footnote-face
+  '((t (:inherit markdown-markup-face)))
+  "Face for footnote markers."
+  :group 'markdown-faces)
+
+(defface markdown-url-face
+  '((t (:inherit font-lock-string-face)))
+  "Face for URLs."
+  :group 'markdown-faces)
+
+(defface markdown-link-title-face
+  '((t (:inherit font-lock-comment-face)))
+  "Face for reference link titles."
+  :group 'markdown-faces)
+
+(defface markdown-line-break-face
+  '((t (:inherit font-lock-constant-face :underline t)))
+  "Face for hard line breaks."
+  :group 'markdown-faces)
+
+(defface markdown-comment-face
+  '((t (:inherit font-lock-comment-face)))
+  "Face for HTML comments."
+  :group 'markdown-faces)
+
+(defface markdown-math-face
+  '((t (:inherit font-lock-string-face)))
+  "Face for LaTeX expressions."
+  :group 'markdown-faces)
+
+(defface markdown-metadata-key-face
+  '((t (:inherit font-lock-variable-name-face)))
+  "Face for metadata keys."
+  :group 'markdown-faces)
+
+(defface markdown-metadata-value-face
+  '((t (:inherit font-lock-string-face)))
+  "Face for metadata values."
+  :group 'markdown-faces)
+
+(defface markdown-gfm-checkbox-face
+  '((t (:inherit font-lock-builtin-face)))
+  "Face for GFM checkboxes."
+  :group 'markdown-faces)
+
+(defface markdown-highlight-face
+  '((t (:inherit highlight)))
+  "Face for mouse highlighting."
+  :group 'markdown-faces)
+
+(defun markdown-syntactic-face (state)
+  "Returns a font-lock face for characters with given STATE.
+See `font-lock-syntactic-face-function' for details."
+  (let ((in-comment (nth 4 state)))
+    (cond
+     (in-comment 'markdown-comment-face)
+     (t nil))))
+
+(defvar markdown-mode-font-lock-keywords-basic
+  (list
+   (cons 'markdown-match-gfm-code-blocks '((1 markdown-markup-face)
+                                           (2 markdown-language-keyword-face nil t)
+                                           (3 markdown-pre-face)
+                                           (4 markdown-markup-face)))
+   (cons 'markdown-match-fenced-code-blocks '((0 markdown-pre-face)))
+   (cons 'markdown-match-pre-blocks '((0 markdown-pre-face)))
+   (cons 'markdown-match-blockquotes '((1 markdown-markup-face)
+                                       (2 markdown-blockquote-face)))
+   (cons 'markdown-match-heading-1-setext '((1 markdown-header-face-1)
+                                            (2 markdown-header-rule-face)))
+   (cons 'markdown-match-heading-2-setext '((1 markdown-header-face-2)
+                                            (2 markdown-header-rule-face)))
+   (cons 'markdown-match-heading-6-atx '((1 markdown-header-delimiter-face)
+                                         (2 markdown-header-face-6)
+                                         (3 markdown-header-delimiter-face)))
+   (cons 'markdown-match-heading-5-atx '((1 markdown-header-delimiter-face)
+                                         (2 markdown-header-face-5)
+                                         (3 markdown-header-delimiter-face)))
+   (cons 'markdown-match-heading-4-atx '((1 markdown-header-delimiter-face)
+                                         (2 markdown-header-face-4)
+                                         (3 markdown-header-delimiter-face)))
+   (cons 'markdown-match-heading-3-atx '((1 markdown-header-delimiter-face)
+                                         (2 markdown-header-face-3)
+                                         (3 markdown-header-delimiter-face)))
+   (cons 'markdown-match-heading-2-atx '((1 markdown-header-delimiter-face)
+                                         (2 markdown-header-face-2)
+                                         (3 markdown-header-delimiter-face)))
+   (cons 'markdown-match-heading-1-atx '((1 markdown-header-delimiter-face)
+                                         (2 markdown-header-face-1)
+                                         (3 markdown-header-delimiter-face)))
+   (cons 'markdown-match-multimarkdown-metadata '((1 markdown-metadata-key-face)
+                                                  (2 markdown-markup-face)
+                                                  (3 markdown-metadata-value-face)))
+   (cons 'markdown-match-pandoc-metadata '((1 markdown-markup-face)
+                                           (2 markdown-markup-face)
+                                           (3 markdown-metadata-value-face)))
+   (cons 'markdown-match-hr 'markdown-header-delimiter-face)
+   (cons 'markdown-match-code '((1 markdown-markup-face)
+                                (2 markdown-inline-code-face)
+                                (3 markdown-markup-face)))
+   (cons markdown-regex-kbd '((1 markdown-markup-face)
+                              (2 markdown-inline-code-face)
+                              (3 markdown-markup-face)))
+   (cons markdown-regex-angle-uri '((1 markdown-markup-face)
+                                    (2 markdown-link-face)
+                                    (3 markdown-markup-face)))
+   (cons markdown-regex-list '(2 markdown-list-face))
+   (cons markdown-regex-footnote '((1 markdown-markup-face)   ; [^
+                                   (2 markdown-footnote-face) ; label
+                                   (3 markdown-markup-face))) ; ]
+   (cons markdown-regex-link-inline '((1 markdown-markup-face nil t)     ; ! (optional)
+                                      (2 markdown-markup-face)           ; [
+                                      (3 markdown-link-face)             ; text
+                                      (4 markdown-markup-face)           ; ]
+                                      (5 markdown-markup-face)           ; (
+                                      (6 markdown-url-face)              ; url
+                                      (7 markdown-link-title-face nil t) ; "title" (optional)
+                                      (8 markdown-markup-face)))         ; )
+   (cons markdown-regex-link-reference '((1 markdown-markup-face nil t) ; ! (optional)
+                                         (2 markdown-markup-face)       ; [
+                                         (3 markdown-link-face)         ; text
+                                         (4 markdown-markup-face)       ; ]
+                                         (5 markdown-markup-face)       ; [
+                                         (6 markdown-reference-face)    ; label
+                                         (7 markdown-markup-face)))     ; ]
+   (cons markdown-regex-reference-definition '((1 markdown-markup-face)       ; [
+                                               (2 markdown-reference-face)    ; label
+                                               (3 markdown-markup-face)       ; ]
+                                               (4 markdown-markup-face)       ; :
+                                               (5 markdown-url-face)          ; url
+                                               (6 markdown-link-title-face))) ; "title" (optional)
+   ;; Math mode $..$
+   (cons 'markdown-match-math-single '((1 markdown-markup-face prepend)
+                                       (2 markdown-math-face append)
+                                       (3 markdown-markup-face prepend)))
+   ;; Math mode $$..$$
+   (cons 'markdown-match-math-double '((1 markdown-markup-face prepend)
+                                       (2 markdown-math-face append)
+                                       (3 markdown-markup-face prepend)))
+   (cons 'markdown-match-bold '((1 markdown-markup-face prepend)
+                                (2 markdown-bold-face append)
+                                (3 markdown-markup-face prepend)))
+   (cons 'markdown-match-italic '((1 markdown-markup-face prepend)
+                                  (2 markdown-italic-face append)
+                                  (3 markdown-markup-face prepend)))
+   (cons markdown-regex-uri 'markdown-link-face)
+   (cons markdown-regex-email 'markdown-link-face)
+   (cons markdown-regex-line-break '(1 markdown-line-break-face prepend))
+   )
+  "Syntax highlighting for Markdown files.")
+
+(defconst markdown-mode-font-lock-keywords-math
+  (list
+   ;; Display mode equations with brackets: \[ \]
+   (cons markdown-regex-math-display '((1 markdown-markup-face prepend)
+                                       (2 markdown-math-face append)
+                                       (3 markdown-markup-face prepend)))
+   ;; Equation reference (eq:foo)
+   (cons "\\((eq:\\)\\([[:alnum:]:_]+\\)\\()\\)" '((1 markdown-markup-face)
+                                                   (2 markdown-reference-face)
+                                                   (3 markdown-markup-face)))
+   ;; Equation reference \eqref{foo}
+   (cons "\\(\\\\eqref{\\)\\([[:alnum:]:_]+\\)\\(}\\)" '((1 markdown-markup-face)
+                                                         (2 markdown-reference-face)
+                                                         (3 markdown-markup-face))))
+  "Syntax highlighting for LaTeX and itex fragments.")
+
+(defvar markdown-mode-font-lock-keywords nil
+  "Default highlighting expressions for Markdown mode.
+This variable is defined as a buffer-local variable for dynamic
+extension support.")
+
+;; Footnotes
+(defvar markdown-footnote-counter 0
+  "Counter for footnote numbers.")
+(make-variable-buffer-local 'markdown-footnote-counter)
+
+(defconst markdown-footnote-chars
+  "[[:alnum:]-]"
+  "Regular expression maching any character that is allowed in a footnote identifier.")
+
+(defconst markdown-regex-footnote-definition
+  (concat "^\\[\\(\\^" markdown-footnote-chars "*?\\)\\]:\\(?:[ \t]+\\|$\\)")
+  "Regular expression matching a footnote definition, capturing the label.")
+
+
+;;; Compatibility =============================================================
+
+(defun markdown-replace-regexp-in-string (regexp rep string)
+  "Replace ocurrences of REGEXP with REP in STRING.
+This is a compatibility wrapper to provide `replace-regexp-in-string'
+in XEmacs 21."
+  (if (featurep 'xemacs)
+      (replace-in-string string regexp rep)
+    (replace-regexp-in-string regexp rep string)))
+
+;; `markdown-use-region-p' is a compatibility function which checks
+;; for an active region, with fallbacks for older Emacsen and XEmacs.
+(eval-and-compile
+  (cond
+   ;; Emacs 23 and newer
+   ((fboundp 'use-region-p)
+    (defalias 'markdown-use-region-p 'use-region-p))
+   ;; Older Emacsen
+   ((and (boundp 'transient-mark-mode) (boundp 'mark-active))
+    (defun markdown-use-region-p ()
+      "Compatibility wrapper to provide `use-region-p'."
+      (and transient-mark-mode mark-active)))
+   ;; XEmacs
+   ((fboundp 'region-active-p)
+    (defalias 'markdown-use-region-p 'region-active-p))))
+
+(defun markdown-use-buttons-p ()
+  "Determine whether this Emacs supports buttons."
+  (or (featurep 'button) (locate-library "button")))
+
+;; Use new names for outline-mode functions in Emacs 25 and later.
+(eval-and-compile
+  (defalias 'markdown-hide-sublevels
+    (if (fboundp 'outline-hide-sublevels)
+        'outline-hide-sublevels
+      'hide-sublevels))
+  (defalias 'markdown-show-all
+    (if (fboundp 'outline-show-all)
+        'outline-show-all
+      'show-all))
+  (defalias 'markdown-hide-body
+    (if (fboundp 'outline-hide-body)
+        'outline-hide-body
+      'hide-body))
+  (defalias 'markdown-show-entry
+    (if (fboundp 'outline-show-entry)
+        'outline-show-entry
+      'show-entry))
+  (defalias 'markdown-show-children
+    (if (fboundp 'outline-show-children)
+        'outline-show-children
+      'show-children))
+  (defalias 'markdown-show-subtree
+    (if (fboundp 'outline-show-subtree)
+        'outline-show-subtree
+      'show-subtree))
+  (defalias 'markdown-hide-subtree
+    (if (fboundp 'outline-hide-subtree)
+        'outline-hide-subtree
+      'hide-subtree)))
+
+
+;;; Markdown Parsing Functions ================================================
+
+(defun markdown-cur-line-blank-p ()
+  "Return t if the current line is blank and nil otherwise."
+  (save-match-data
+    (save-excursion
+      (beginning-of-line)
+      (re-search-forward "^\\s *$" (line-end-position) t))))
+
+(defun markdown-prev-line-blank-p ()
+  "Return t if the previous line is blank and nil otherwise.
+If we are at the first line, then consider the previous line to be blank."
+  (or (= (line-beginning-position) (point-min))
+      (save-excursion
+        (forward-line -1)
+        (markdown-cur-line-blank-p))))
+
+(defun markdown-next-line-blank-p ()
+  "Return t if the next line is blank and nil otherwise.
+If we are at the last line, then consider the next line to be blank."
+  (or (= (line-end-position) (point-max))
+      (save-excursion
+        (forward-line 1)
+        (markdown-cur-line-blank-p))))
+
+(defun markdown-prev-line-indent-p ()
+  "Return t if the previous line is indented and nil otherwise."
+  (save-excursion
+    (if (= (line-beginning-position) (point-min))
+        nil
+      (forward-line -1)
+      (goto-char (line-beginning-position))
+      (if (re-search-forward "^\\s " (line-end-position) t) t))))
+
+(defun markdown-cur-line-indent ()
+  "Return the number of leading whitespace characters in the current line."
+  (save-match-data
+    (save-excursion
+      (goto-char (line-beginning-position))
+      (re-search-forward "^[ \t]+" (line-end-position) t)
+      (current-column))))
+
+(defun markdown-prev-line-indent ()
+  "Return the number of leading whitespace characters in the previous line.
+Return 0 if the current line is the first line in the buffer."
+  (save-excursion
+    (if (= (line-beginning-position) (point-min))
+        0
+      (forward-line -1)
+      (markdown-cur-line-indent))))
+
+(defun markdown-next-line-indent ()
+  "Return the number of leading whitespace characters in the next line.
+Return 0 if line is the last line in the buffer."
+  (save-excursion
+    (if (= (line-end-position) (point-max))
+        0
+      (forward-line 1)
+      (markdown-cur-line-indent))))
+
+(defun markdown-cur-non-list-indent ()
+  "Return beginning position of list item text (not including the list marker).
+Return nil if the current line is not the beginning of a list item."
+  (save-match-data
+    (save-excursion
+      (beginning-of-line)
+      (when (re-search-forward markdown-regex-list (line-end-position) t)
+        (current-column)))))
+
+(defun markdown-prev-non-list-indent ()
+  "Return position of the first non-list-marker on the previous line."
+  (save-excursion
+    (forward-line -1)
+    (markdown-cur-non-list-indent)))
+
+(defun markdown-new-baseline-p ()
+  "Determine if the current line begins a new baseline level."
+  (save-excursion
+    (beginning-of-line)
+    (save-match-data
+      (or (looking-at markdown-regex-header)
+          (looking-at markdown-regex-hr)
+          (and (null (markdown-cur-non-list-indent))
+               (= (markdown-cur-line-indent) 0)
+               (markdown-prev-line-blank-p))))))
+
+(defun markdown-search-backward-baseline ()
+  "Search backward baseline point with no indentation and not a list item."
+  (end-of-line)
+  (let (stop)
+    (while (not (or stop (bobp)))
+      (re-search-backward markdown-regex-block-separator nil t)
+      (when (match-end 2)
+        (goto-char (match-end 2))
+        (cond
+         ((markdown-new-baseline-p)
+          (setq stop t))
+         ((looking-at markdown-regex-list)
+          (setq stop nil))
+         (t (setq stop t)))))))
+
+(defun markdown-update-list-levels (marker indent levels)
+  "Update list levels given list MARKER, block INDENT, and current LEVELS.
+Here, MARKER is a string representing the type of list, INDENT is an integer
+giving the indentation, in spaces, of the current block, and LEVELS is a
+list of the indentation levels of parent list items.  When LEVELS is nil,
+it means we are at baseline (not inside of a nested list)."
+  (cond
+   ;; New list item at baseline.
+   ((and marker (null levels))
+    (setq levels (list indent)))
+   ;; List item with greater indentation (four or more spaces).
+   ;; Increase list level.
+   ((and marker (>= indent (+ (car levels) 4)))
+    (setq levels (cons indent levels)))
+   ;; List item with greater or equal indentation (less than four spaces).
+   ;; Do not increase list level.
+   ((and marker (>= indent (car levels)))
+    levels)
+   ;; Lesser indentation level.
+   ;; Pop appropriate number of elements off LEVELS list (e.g., lesser
+   ;; indentation could move back more than one list level).  Note
+   ;; that this block need not be the beginning of list item.
+   ((< indent (car levels))
+    (while (and (> (length levels) 1)
+                (< indent (+ (cadr levels) 4)))
+      (setq levels (cdr levels)))
+    levels)
+   ;; Otherwise, do nothing.
+   (t levels)))
+
+(defun markdown-calculate-list-levels ()
+  "Calculate list levels at point.
+Return a list of the form (n1 n2 n3 ...) where n1 is the
+indentation of the deepest nested list item in the branch of
+the list at the point, n2 is the indentation of the parent
+list item, and so on.  The depth of the list item is therefore
+the length of the returned list.  If the point is not at or
+immediately  after a list item, return nil."
+  (save-excursion
+    (let ((first (point)) levels indent pre-regexp)
+      ;; Find a baseline point with zero list indentation
+      (markdown-search-backward-baseline)
+      ;; Search for all list items between baseline and LOC
+      (while (and (< (point) first)
+                  (re-search-forward markdown-regex-list first t))
+        (setq pre-regexp (format "^\\(    \\|\t\\)\\{%d\\}" (1+ (length levels))))
+        (beginning-of-line)
+        (cond
+         ;; Make sure this is not a header or hr
+         ((markdown-new-baseline-p) (setq levels nil))
+         ;; Make sure this is not a line from a pre block
+         ((looking-at pre-regexp))
+         ;; If not, then update levels
+         (t
+          (setq indent (markdown-cur-line-indent))
+          (setq levels (markdown-update-list-levels (match-string 2)
+                                                    indent levels))))
+        (end-of-line))
+      levels)))
+
+(defun markdown-prev-list-item (level)
+  "Search backward from point for a list item with indentation LEVEL.
+Set point to the beginning of the item, and return point, or nil
+upon failure."
+  (let (bounds indent prev)
+    (setq prev (point))
+    (forward-line -1)
+    (setq indent (markdown-cur-line-indent))
+    (while
+        (cond
+         ;; List item
+         ((and (looking-at markdown-regex-list)
+               (setq bounds (markdown-cur-list-item-bounds)))
+          (cond
+           ;; Stop and return point at item of lesser or equal indentation
+           ((<= (nth 3 bounds) level)
+            (setq prev (point))
+            nil)
+           ;; Stop at beginning of buffer
+           ((bobp) (setq prev nil))
+           ;; Continue at item with greater indentation
+           ((> (nth 3 bounds) level) t)))
+         ;; Stop at beginning of buffer
+         ((bobp) (setq prev nil))
+         ;; Continue if current line is blank
+         ((markdown-cur-line-blank-p) t)
+         ;; Continue while indentation is the same or greater
+         ((>= indent level) t)
+         ;; Stop if current indentation is less than list item
+         ;; and the next is blank
+         ((and (< indent level)
+               (markdown-next-line-blank-p))
+          (setq prev nil))
+         ;; Stop at a header
+         ((looking-at markdown-regex-header) (setq prev nil))
+         ;; Stop at a horizontal rule
+         ((looking-at markdown-regex-hr) (setq prev nil))
+         ;; Otherwise, continue.
+         (t t))
+      (forward-line -1)
+      (setq indent (markdown-cur-line-indent)))
+    prev))
+
+(defun markdown-next-list-item (level)
+  "Search forward from point for the next list item with indentation LEVEL.
+Set point to the beginning of the item, and return point, or nil
+upon failure."
+  (let (bounds indent prev next)
+    (setq next (point))
+    (forward-line)
+    (setq indent (markdown-cur-line-indent))
+    (while
+        (cond
+         ;; Stop at end of the buffer.
+         ((eobp) (setq prev nil))
+         ;; Continue if the current line is blank
+         ((markdown-cur-line-blank-p) t)
+         ;; List item
+         ((and (looking-at markdown-regex-list)
+               (setq bounds (markdown-cur-list-item-bounds)))
+          (cond
+           ;; Continue at item with greater indentation
+           ((> (nth 3 bounds) level) t)
+           ;; Stop and return point at item of equal indentation
+           ((= (nth 3 bounds) level)
+            (setq next (point))
+            nil)
+           ;; Stop and return nil at item with lesser indentation
+           ((< (nth 3 bounds) level)
+            (setq next nil)
+            nil)))
+         ;; Continue while indentation is the same or greater
+         ((>= indent level) t)
+         ;; Stop if current indentation is less than list item
+         ;; and the previous line was blank.
+         ((and (< indent level)
+               (markdown-prev-line-blank-p))
+          (setq next nil))
+         ;; Stop at a header
+         ((looking-at markdown-regex-header) (setq next nil))
+         ;; Stop at a horizontal rule
+         ((looking-at markdown-regex-hr) (setq next nil))
+         ;; Otherwise, continue.
+         (t t))
+      (forward-line)
+      (setq indent (markdown-cur-line-indent)))
+    next))
+
+(defun markdown-cur-list-item-end (level)
+  "Move to the end of the current list item with nonlist indentation LEVEL.
+If the point is not in a list item, do nothing."
+  (let (indent)
+    (forward-line)
+    (setq indent (markdown-cur-line-indent))
+    (while
+        (cond
+         ;; Stop at end of the buffer.
+         ((eobp) nil)
+         ;; Continue if the current line is blank
+         ((markdown-cur-line-blank-p) t)
+         ;; Continue while indentation is the same or greater
+         ((>= indent level) t)
+         ;; Stop if current indentation is less than list item
+         ;; and the previous line was blank.
+         ((and (< indent level)
+               (markdown-prev-line-blank-p))
+          nil)
+         ;; Stop at a new list item of the same or lesser indentation
+         ((looking-at markdown-regex-list) nil)
+         ;; Stop at a header
+         ((looking-at markdown-regex-header) nil)
+         ;; Stop at a horizontal rule
+         ((looking-at markdown-regex-hr) nil)
+         ;; Otherwise, continue.
+         (t t))
+      (forward-line)
+      (setq indent (markdown-cur-line-indent)))
+    ;; Don't skip over whitespace for empty list items (marker and
+    ;; whitespace only), just move to end of whitespace.
+    (if (looking-back (concat markdown-regex-list "\\s-*") nil)
+          (goto-char (match-end 3))
+      (skip-syntax-backward "-"))))
+
+(defun markdown-cur-list-item-bounds ()
+  "Return bounds and indentation of the current list item.
+Return a list of the form (begin end indent nonlist-indent marker).
+If the point is not inside a list item, return nil.
+Leave match data intact for `markdown-regex-list'."
+  (let (cur prev-begin prev-end indent nonlist-indent marker)
+    ;; Store current location
+    (setq cur (point))
+    ;; Verify that cur is between beginning and end of item
+    (save-excursion
+      (end-of-line)
+      (when (re-search-backward markdown-regex-list nil t)
+        (setq prev-begin (match-beginning 0))
+        (setq indent (length (match-string 1)))
+        (setq nonlist-indent (length (match-string 0)))
+        (setq marker (concat (match-string 2) (match-string 3)))
+        (save-match-data
+          (markdown-cur-list-item-end nonlist-indent)
+          (setq prev-end (point)))
+        (when (and (>= cur prev-begin)
+                   (<= cur prev-end)
+                   nonlist-indent)
+          (list prev-begin prev-end indent nonlist-indent marker))))))
+
+(defun markdown-bounds-of-thing-at-point (thing)
+  "Call `bounds-of-thing-at-point' for THING with slight modifications.
+Does not include trailing newlines when THING is 'line.  Handles the
+end of buffer case by setting both endpoints equal to the value of
+`point-max', since an empty region will trigger empty markup insertion.
+Return bounds of form (beg . end) if THING is found, or nil otherwise."
+  (let* ((bounds (bounds-of-thing-at-point thing))
+         (a (car bounds))
+         (b (cdr bounds)))
+    (when bounds
+      (when (eq thing 'line)
+        (cond ((and (eobp) (markdown-cur-line-blank-p))
+               (setq a b))
+              ((char-equal (char-before b) ?\^J)
+               (setq b (1- b)))))
+      (cons a b))))
+
+(defun markdown-reference-definition (reference)
+  "Find out whether Markdown REFERENCE is defined.
+REFERENCE should not include the square brackets.
+When REFERENCE is defined, return a list of the form (text start end)
+containing the definition text itself followed by the start and end
+locations of the text.  Otherwise, return nil.
+Leave match data for `markdown-regex-reference-definition'
+intact additional processing."
+  (let ((reference (downcase reference)))
+    (save-excursion
+      (goto-char (point-min))
+      (catch 'found
+        (while (re-search-forward markdown-regex-reference-definition nil t)
+          (when (string= reference (downcase (match-string-no-properties 2)))
+            (throw 'found
+                   (list (match-string-no-properties 5)
+                         (match-beginning 5) (match-end 5)))))))))
+
+(defun markdown-get-defined-references ()
+  "Return a list of all defined reference labels (not including square brackets)."
+  (save-excursion
+    (goto-char (point-min))
+    (let (refs)
+      (while (re-search-forward markdown-regex-reference-definition nil t)
+        (let ((target (match-string-no-properties 2)))
+          (add-to-list 'refs target t)))
+      refs)))
+
+(defun markdown-code-at-point-p ()
+  "Return non-nil if the point is at an inline code fragment.
+Return nil otherwise.  Set match data according to
+`markdown-match-code' upon success.
+This function searches the block for a code fragment that
+contains the point using `markdown-match-code'.  We do this
+because `thing-at-point-looking-at' does not work reliably with
+`markdown-regex-code'.
+
+The match data is set as follows:
+Group 1 matches the opening backticks.
+Group 2 matches the code fragment itself, without backticks.
+Group 3 matches the closing backticks."
+  (interactive)
+  (save-excursion
+    (let ((old-point (point))
+          (end-of-block (progn (markdown-end-of-block) (point)))
+          found)
+      (markdown-beginning-of-block)
+      (while (and (markdown-match-code end-of-block)
+                  (setq found t)
+                  (< (match-end 0) old-point)))
+      (and found                              ; matched something
+           (<= (match-beginning 0) old-point) ; match contains old-point
+           (>= (match-end 0) old-point)))))
+
+(defun markdown-code-block-at-pos (pos)
+  "Return match data list if there is a code block at POS.
+This includes pre blocks, tilde-fenced code blocks, and GFM
+quoted code blocks.  Return nil otherwise."
+  (or (get-text-property pos 'markdown-pre)
+      (get-text-property pos 'markdown-gfm-code)
+      (get-text-property pos 'markdown-fenced-code)))
+
+(defun markdown-code-block-at-point ()
+  "Return match data if the point is inside a code block.
+This includes pre blocks, tilde-fenced code blocks, and
+GFM quoted code blocks.  Calls `markdown-code-block-at-pos'."
+  (markdown-code-block-at-pos (point)))
+
+
+;;; Markdown Font Lock Matching Functions =====================================
+
+(defun markdown-range-property-any (begin end prop values)
+  "Return t if PROP from BEGIN to END is equal to one of the given VALUES.
+Also returns t if PROP is a list containing one of the VALUES.
+Return nil otherwise."
+  (let (loc props val)
+    (catch 'found
+      (dolist (loc (number-sequence begin end))
+        (when (setq props (get-char-property loc prop))
+          (cond ((listp props)
+                 ;; props is a list, check for membership
+                 (dolist (val values)
+                   (when (memq val props) (throw 'found loc))))
+              (t
+               ;; props is a scalar, check for equality
+               (dolist (val values)
+                 (when (eq val props) (throw 'found loc))))))))))
+
+(defun markdown-match-inline-generic (regex last)
+  "Match inline REGEX from the point to LAST."
+  (when (re-search-forward regex last t)
+    (let ((bounds (markdown-code-block-at-pos (match-beginning 0))))
+      (if (null bounds)
+          ;; Not in a code block: keep match data and return t when in bounds
+          (<= (match-end 0) last)
+        ;; In code block: move past it and recursively search again
+        (when (< (goto-char (nth 1 bounds)) last)
+          (markdown-match-inline-generic regex last))))))
+
+(defun markdown-match-code (last)
+  "Match inline code fragments from point to LAST."
+  (unless (bobp)
+    (backward-char 1))
+  (when (markdown-match-inline-generic markdown-regex-code last)
+    (set-match-data (list (match-beginning 1) (match-end 1)
+                          (match-beginning 2) (match-end 2)
+                          (match-beginning 3) (match-end 3)
+                          (match-beginning 4) (match-end 4)))
+    (goto-char (1+ (match-end 0)))))
+
+(defun markdown-match-bold (last)
+  "Match inline bold from the point to LAST."
+  (when (markdown-match-inline-generic markdown-regex-bold last)
+    (set-match-data (list (match-beginning 2) (match-end 2)
+                          (match-beginning 3) (match-end 3)
+                          (match-beginning 4) (match-end 4)
+                          (match-beginning 5) (match-end 5)))
+    (goto-char (1+ (match-end 0)))))
+
+(defun markdown-match-italic (last)
+  "Match inline italics from the point to LAST."
+  (let ((regex (if (eq major-mode 'gfm-mode)
+                   markdown-regex-gfm-italic markdown-regex-italic)))
+    (when (markdown-match-inline-generic regex last)
+      (let ((begin (match-beginning 1)) (end (match-end 1)))
+        (cond
+         ((markdown-range-property-any
+           begin end 'face (list markdown-inline-code-face
+                                 markdown-bold-face
+                                 markdown-math-face))
+          (goto-char (1+ (match-end 0)))
+          (markdown-match-italic last))
+         (t
+          (set-match-data (list (match-beginning 1) (match-end 1)
+                                (match-beginning 2) (match-end 2)
+                                (match-beginning 3) (match-end 3)
+                                (match-beginning 4) (match-end 4)))
+          (goto-char (1+ (match-end 0)))))))))
+
+(defun markdown-match-math-generic (regex last)
+  "Match quoted $..$ or $$..$$ math from point to LAST."
+  (when (and markdown-enable-math
+             (markdown-match-inline-generic regex last))
+    (let ((begin (match-beginning 1)) (end (match-end 1)))
+      (prog1
+          (if (markdown-range-property-any
+               begin end 'face (list markdown-inline-code-face
+                                     markdown-bold-face))
+              (markdown-match-math-generic regex last)
+            t)
+        (goto-char (1+ (match-end 0)))))))
+
+(defun markdown-match-math-single (last)
+  "Match single quoted $..$ math from point to LAST."
+  (markdown-match-math-generic markdown-regex-math-inline-single last))
+
+(defun markdown-match-math-double (last)
+  "Match double quoted $$..$$ math from point to LAST."
+  (markdown-match-math-generic markdown-regex-math-inline-double last))
+
+(defun markdown-match-propertized-text (property last)
+  "Match text with PROPERTY from point to LAST.
+Restore match data previously stored in PROPERTY."
+  (let (saved pos)
+    (unless (setq saved (get-text-property (point) property))
+      (setq pos (next-single-char-property-change (point) property nil last))
+      (setq saved (get-text-property pos property)))
+    (when saved
+      (set-match-data saved)
+      (goto-char (min (1+ (match-end 0)) (point-max)))
+      saved)))
+
+(defun markdown-match-pre-blocks (last)
+  "Match preformatted blocks from point to LAST.
+Use data stored in 'markdown-pre text property during syntax
+analysis."
+  (markdown-match-propertized-text 'markdown-pre last))
+
+(defun markdown-match-gfm-code-blocks (last)
+  "Match GFM quoted code blocks from point to LAST.
+Use data stored in 'markdown-gfm-code text property during syntax
+analysis."
+  (markdown-match-propertized-text 'markdown-gfm-code last))
+
+(defun markdown-match-fenced-code-blocks (last)
+  "Match fenced code blocks from the point to LAST."
+  (markdown-match-propertized-text 'markdown-fenced-code last))
+
+(defun markdown-match-blockquotes (last)
+  "Match blockquotes from point to LAST.
+Use data stored in 'markdown-blockquote text property during syntax
+analysis."
+  (markdown-match-propertized-text 'markdown-blockquote last))
+
+(defun markdown-match-heading-1-setext (last)
+  "Match level 1 setext headings from point to LAST."
+  (markdown-match-propertized-text 'markdown-heading-1-setext last))
+
+(defun markdown-match-heading-2-setext (last)
+  "Match level 2 setext headings from point to LAST."
+  (markdown-match-propertized-text 'markdown-heading-2-setext last))
+
+(defun markdown-match-heading-1-atx (last)
+  "Match level 1 ATX headings from point to LAST."
+  (markdown-match-propertized-text 'markdown-heading-1-atx last))
+
+(defun markdown-match-heading-2-atx (last)
+  "Match level 2 ATX headings from point to LAST."
+  (markdown-match-propertized-text 'markdown-heading-2-atx last))
+
+(defun markdown-match-heading-3-atx (last)
+  "Match level 3 ATX headings from point to LAST."
+  (markdown-match-propertized-text 'markdown-heading-3-atx last))
+
+(defun markdown-match-heading-4-atx (last)
+  "Match level 4 ATX headings from point to LAST."
+  (markdown-match-propertized-text 'markdown-heading-4-atx last))
+
+(defun markdown-match-heading-5-atx (last)
+  "Match level 5 ATX headings from point to LAST."
+  (markdown-match-propertized-text 'markdown-heading-5-atx last))
+
+(defun markdown-match-heading-6-atx (last)
+  "Match level 6 ATX headings from point to LAST."
+  (markdown-match-propertized-text 'markdown-heading-6-atx last))
+
+(defun markdown-match-hr (last)
+  "Match horizontal rules comments from the point to LAST."
+  (while (and (re-search-forward markdown-regex-hr last t)
+              (or (markdown-on-heading-p)
+                  (markdown-code-block-at-point))
+              (< (match-end 0) last))
+    (forward-line))
+  (beginning-of-line)
+  (cond ((looking-at markdown-regex-hr)
+         (forward-line)
+         t)
+        (t nil)))
+
+(defun markdown-match-comments (last)
+  "Match HTML comments from the point to LAST."
+  (when (and (skip-syntax-forward "^<" last))
+    (let ((beg (point)))
+      (when (and (skip-syntax-forward "^>" last) (< (point) last))
+        (forward-char)
+        (set-match-data (list beg (point)))
+        t))))
+
+(defun markdown-match-generic-metadata (regexp last)
+  "Match generic metadata specified by REGEXP from the point to LAST."
+  (let ((header-end (save-excursion
+                      (goto-char (point-min))
+                      (if (re-search-forward "\n\n" (point-max) t)
+                          (match-beginning 0)
+                        (point-max)))))
+    (cond ((>= (point) header-end)
+           ;; Don't match anything outside of the header.
+           nil)
+          ((re-search-forward regexp (min last header-end) t)
+           ;; If a metadata item is found, it may span several lines.
+           (let ((key-beginning (match-beginning 1))
+                 (key-end (match-end 1))
+                 (markup-begin (match-beginning 2))
+                 (markup-end (match-end 2))
+                 (value-beginning (match-beginning 3)))
+             (while (and (not (looking-at regexp))
+                         (not (> (point) (min last header-end)))
+                         (not (eobp)))
+               (forward-line))
+             (unless (eobp)
+               (forward-line -1)
+               (end-of-line))
+             (set-match-data (list key-beginning (point) ; complete metadata
+                                   key-beginning key-end ; key
+                                   markup-begin markup-end ; markup
+                                   value-beginning (point))) ; value
+           t))
+          (t nil))))
+
+(defun markdown-match-multimarkdown-metadata (last)
+  "Match MultiMarkdown metadata from the point to LAST."
+  (markdown-match-generic-metadata markdown-regex-multimarkdown-metadata last))
+
+(defun markdown-match-pandoc-metadata (last)
+  "Match Pandoc metadata from the point to LAST."
+  (markdown-match-generic-metadata markdown-regex-pandoc-metadata last))
+
+
+;;; Syntax Table ==============================================================
+
+(defvar markdown-mode-syntax-table
+  (let ((tab (make-syntax-table text-mode-syntax-table)))
+    (modify-syntax-entry ?\" "." tab)
+    tab)
+  "Syntax table for `markdown-mode'.")
+
+
+;;; Element Insertion =========================================================
+
+(defun markdown-ensure-blank-line-before ()
+  "If previous line is not already blank, insert a blank line before point."
+  (unless (bolp) (insert "\n"))
+  (unless (or (bobp) (looking-back "\n\\s-*\n" nil)) (insert "\n")))
+
+(defun markdown-ensure-blank-line-after ()
+  "If following line is not already blank, insert a blank line after point.
+Return the point where it was originally."
+  (save-excursion
+    (unless (eolp) (insert "\n"))
+    (unless (or (eobp) (looking-at "\n\\s-*\n")) (insert "\n"))))
+
+(defun markdown-wrap-or-insert (s1 s2 &optional thing beg end)
+  "Insert the strings S1 and S2, wrapping around region or THING.
+If a region is specified by the optional BEG and END arguments,
+wrap the strings S1 and S2 around that region.
+If there is an active region, wrap the strings S1 and S2 around
+the region.  If there is not an active region but the point is at
+THING, wrap that thing (which defaults to word).  Otherwise, just
+insert S1 and S2 and place the cursor in between.  Return the
+bounds of the entire wrapped string, or nil if nothing was wrapped
+and S1 and S2 were only inserted."
+  (let (a b bounds new-point)
+    (cond
+     ;; Given region
+     ((and beg end)
+      (setq a beg
+            b end
+            new-point (+ (point) (length s1))))
+     ;; Active region
+     ((markdown-use-region-p)
+      (setq a (region-beginning)
+            b (region-end)
+            new-point (+ (point) (length s1))))
+     ;; Thing (word) at point
+     ((setq bounds (markdown-bounds-of-thing-at-point (or thing 'word)))
+      (setq a (car bounds)
+            b (cdr bounds)
+            new-point (+ (point) (length s1))))
+     ;; No active region and no word
+     (t
+      (setq a (point)
+            b (point))))
+    (goto-char b)
+    (insert s2)
+    (goto-char a)
+    (insert s1)
+    (when new-point (goto-char new-point))
+    (if (= a b)
+        nil
+      (setq b (+ b (length s1) (length s2)))
+      (cons a b))))
+
+(defun markdown-point-after-unwrap (cur prefix suffix)
+  "Return desired position of point after an unwrapping operation.
+CUR gives the position of the point before the operation.
+Additionally, two cons cells must be provided.  PREFIX gives the
+bounds of the prefix string and SUFFIX gives the bounds of the
+suffix string."
+  (cond ((< cur (cdr prefix)) (car prefix))
+        ((< cur (car suffix)) (- cur (- (cdr prefix) (car prefix))))
+        ((<= cur (cdr suffix))
+         (- cur (+ (- (cdr prefix) (car prefix))
+                   (- cur (car suffix)))))
+        (t cur)))
+
+(defun markdown-unwrap-thing-at-point (regexp all text)
+  "Remove prefix and suffix of thing at point and reposition the point.
+When the thing at point matches REGEXP, replace the subexpression
+ALL with the string in subexpression TEXT.  Reposition the point
+in an appropriate location accounting for the removal of prefix
+and suffix strings.  Return new bounds of string from group TEXT.
+When REGEXP is nil, assumes match data is already set."
+  (when (or (null regexp)
+            (thing-at-point-looking-at regexp))
+    (let ((cur (point))
+          (prefix (cons (match-beginning all) (match-beginning text)))
+          (suffix (cons (match-end text) (match-end all)))
+          (bounds (cons (match-beginning text) (match-end text))))
+      ;; Replace the thing at point
+      (replace-match (match-string text) t t nil all)
+      ;; Reposition the point
+      (goto-char (markdown-point-after-unwrap cur prefix suffix))
+      ;; Adjust bounds
+      (setq bounds (cons (car prefix)
+                         (- (cdr bounds) (- (cdr prefix) (car prefix))))))))
+
+(defun markdown-unwrap-things-in-region (beg end regexp all text)
+  "Remove prefix and suffix of all things in region from BEG to END.
+When a thing in the region matches REGEXP, replace the
+subexpression ALL with the string in subexpression TEXT.
+Return a cons cell containing updated bounds for the region."
+  (save-excursion
+    (goto-char beg)
+    (let ((removed 0) len-all len-text)
+      (while (re-search-forward regexp (- end removed) t)
+        (setq len-all (length (match-string-no-properties all)))
+        (setq len-text (length (match-string-no-properties text)))
+        (setq removed (+ removed (- len-all len-text)))
+        (replace-match (match-string text) t t nil all))
+      (cons beg (- end removed)))))
+
+(defun markdown-insert-hr (arg)
+  "Insert or replace a horizonal rule.
+By default, use the first element of `markdown-hr-strings'.  When
+ARG is non-nil, as when given a prefix, select a different
+element as follows.  When prefixed with \\[universal-argument],
+use the last element of `markdown-hr-strings' instead.  When
+prefixed with an integer from 1 to the length of
+`markdown-hr-strings', use the element in that position instead."
+  (interactive "*P")
+  (when (thing-at-point-looking-at markdown-regex-hr)
+    (delete-region (match-beginning 0) (match-end 0)))
+  (markdown-ensure-blank-line-before)
+  (cond ((equal arg '(4))
+         (insert (car (reverse markdown-hr-strings))))
+        ((and (integerp arg) (> arg 0)
+              (<= arg (length markdown-hr-strings)))
+         (insert (nth (1- arg) markdown-hr-strings)))
+        (t
+         (insert (car markdown-hr-strings))))
+  (markdown-ensure-blank-line-after))
+
+(defun markdown-insert-bold ()
+  "Insert markup to make a region or word bold.
+If there is an active region, make the region bold.  If the point
+is at a non-bold word, make the word bold.  If the point is at a
+bold word or phrase, remove the bold markup.  Otherwise, simply
+insert bold delimiters and place the cursor in between them."
+  (interactive)
+  (let ((delim (if markdown-bold-underscore "__" "**")))
+    (if (markdown-use-region-p)
+        ;; Active region
+        (let ((bounds (markdown-unwrap-things-in-region
+                       (region-beginning) (region-end)
+                       markdown-regex-bold 2 4)))
+          (markdown-wrap-or-insert delim delim nil (car bounds) (cdr bounds)))
+      ;; Bold markup removal, bold word at point, or empty markup insertion
+      (if (thing-at-point-looking-at markdown-regex-bold)
+          (markdown-unwrap-thing-at-point nil 2 4)
+        (markdown-wrap-or-insert delim delim 'word nil nil)))))
+
+(defun markdown-insert-italic ()
+  "Insert markup to make a region or word italic.
+If there is an active region, make the region italic.  If the point
+is at a non-italic word, make the word italic.  If the point is at an
+italic word or phrase, remove the italic markup.  Otherwise, simply
+insert italic delimiters and place the cursor in between them."
+  (interactive)
+  (let ((delim (if markdown-italic-underscore "_" "*")))
+    (if (markdown-use-region-p)
+        ;; Active region
+        (let ((bounds (markdown-unwrap-things-in-region
+                       (region-beginning) (region-end)
+                       markdown-regex-italic 1 3)))
+          (markdown-wrap-or-insert delim delim nil (car bounds) (cdr bounds)))
+      ;; Italic markup removal, italic word at point, or empty markup insertion
+      (if (thing-at-point-looking-at markdown-regex-italic)
+          (markdown-unwrap-thing-at-point nil 1 3)
+        (markdown-wrap-or-insert delim delim 'word nil nil)))))
+
+(defun markdown-insert-strike-through ()
+  "Insert markup to make a region or word strikethrough.
+If there is an active region, make the region strikethrough.  If the point
+is at a non-bold word, make the word strikethrough.  If the point is at a
+strikethrough word or phrase, remove the strikethrough markup.  Otherwise,
+simply insert bold delimiters and place the cursor in between them."
+  (interactive)
+  (let ((delim "~~"))
+    (if (markdown-use-region-p)
+        ;; Active region
+        (let ((bounds (markdown-unwrap-things-in-region
+                       (region-beginning) (region-end)
+                       markdown-regex-strike-through 2 4)))
+          (markdown-wrap-or-insert delim delim nil (car bounds) (cdr bounds)))
+      ;; Strikethrough markup removal, strikethrough word at point, or empty markup insertion
+      (if (thing-at-point-looking-at markdown-regex-strike-through)
+          (markdown-unwrap-thing-at-point nil 2 4)
+        (markdown-wrap-or-insert delim delim 'word nil nil)))))
+
+(defun markdown-insert-code ()
+  "Insert markup to make a region or word an inline code fragment.
+If there is an active region, make the region an inline code
+fragment.  If the point is at a word, make the word an inline
+code fragment.  Otherwise, simply insert code delimiters and
+place the cursor in between them."
+  (interactive)
+  (if (markdown-use-region-p)
+      ;; Active region
+      (let ((bounds (markdown-unwrap-things-in-region
+                     (region-beginning) (region-end)
+                     markdown-regex-code 1 3)))
+        (markdown-wrap-or-insert "`" "`" nil (car bounds) (cdr bounds)))
+    ;; Code markup removal, code markup for word, or empty markup insertion
+    (if (markdown-code-at-point-p)
+        (markdown-unwrap-thing-at-point nil 0 2)
+      (markdown-wrap-or-insert "`" "`" 'word nil nil))))
+
+(defun markdown-insert-link ()
+  "Insert an inline link, using region or word as link text if possible.
+If there is an active region, use the region as the link text.  If the
+point is at a word, use the word as the link text.  In these cases, the
+point will be left at the position for inserting a URL.  If there is no
+active region and the point is not at word, simply insert link markup and
+place the point in the position to enter link text."
+  (interactive)
+  (let ((bounds (markdown-wrap-or-insert "[" "]()")))
+    (when bounds
+      (goto-char (- (cdr bounds) 1)))))
+
+(defun markdown-insert-reference-link (text label &optional url title)
+  "Insert a reference link and, optionally, a reference definition.
+The link TEXT will be inserted followed by the optional LABEL.
+If a URL is given, also insert a definition for the reference
+LABEL according to `markdown-reference-location'.  If a TITLE is
+given, it will be added to the end of the reference definition
+and will be used to populate the title attribute when converted
+to XHTML.  If URL is nil, insert only the link portion (for
+example, when a reference label is already defined)."
+  (insert (concat "[" text "][" label "]"))
+  (when url
+    (let ((end (point))
+          (label (if (> (length label) 0) label text)))
+      (cond
+       ((eq markdown-reference-location 'end) (goto-char (point-max)))
+       ((eq markdown-reference-location 'immediately) (markdown-end-of-block))
+       ((eq markdown-reference-location 'header) (markdown-end-of-defun)))
+      (unless (markdown-cur-line-blank-p) (insert "\n"))
+      (insert "\n[" label "]: " url)
+      (unless (> (length url) 0)
+        (setq end (point)))
+      (when (> (length title) 0)
+        (insert " \"" title "\""))
+      (insert "\n")
+      (unless (or (eobp) (looking-at "\n"))
+        (insert "\n"))
+      (goto-char end)
+      (when (> (length url) 0)
+        (message
+         (substitute-command-keys
+          "Defined reference [%s], press \\[markdown-jump] to jump there")
+         (or label text))))))
+
+(defun markdown-insert-reference-link-dwim ()
+  "Insert a reference link of the form [text][label] at point.
+If there is an active region, the text in the region will be used
+as the link text.  If the point is at an inline link, it will be
+converted to a reference link.  If the point is at a word, it will
+be used as the link text.  Otherwise, the link text will be read from
+the minibuffer.  The link label will be read from the minibuffer in
+both cases, with completion from the set of currently defined
+references.  To create an implicit reference link, press RET to
+accept the default, an empty label.  If the entered referenced
+label is not defined, additionally prompt for the URL
+and (optional) title.  The reference definition is placed at the
+location determined by `markdown-reference-location'."
+  (interactive)
+  (let* ((defined-labels (mapcar (lambda (x) (substring x 1 -1))
+                                 (markdown-get-defined-references)))
+         (switch (thing-at-point-looking-at markdown-regex-link-inline))
+         (bounds (cond ((markdown-use-region-p)
+                        (cons (region-beginning) (region-end)))
+                       (switch
+                        (cons (match-beginning 0) (match-end 0)))
+                       (t
+                        (markdown-bounds-of-thing-at-point 'word))))
+         (text (cond (switch (match-string 3))
+                     (bounds (buffer-substring (car bounds) (cdr bounds)))
+                     (t (read-string "Link Text: "))))
+         (label (completing-read
+                 "Link Label (default: none): " defined-labels
+                 nil nil nil 'markdown-reference-label-history nil))
+         (ref (save-match-data
+                (markdown-reference-definition
+                 (if (> (length label) 0) label text))))
+         (url (cond (ref nil)
+                    (switch (match-string 6))
+                    (t (read-string "Link URL: "))))
+         (title (cond
+                 ((= (length url) 0) nil)
+                 (switch (if (> (length (match-string 7)) 2)
+                             (substring (match-string 7) 1 -1)
+                           nil))
+                 (t (read-string "Link Title (optional): ")))))
+    (when bounds (delete-region (car bounds) (cdr bounds)))
+    (markdown-insert-reference-link text label url title)))
+
+(defun markdown-insert-uri ()
+  "Insert markup for an inline URI.
+If there is an active region, use it as the URI.  If the point is
+at a URI, wrap it with angle brackets.  If the point is at an
+inline URI, remove the angle brackets.  Otherwise, simply insert
+angle brackets place the point between them."
+  (interactive)
+  (if (markdown-use-region-p)
+      ;; Active region
+      (let ((bounds (markdown-unwrap-things-in-region
+                     (region-beginning) (region-end)
+                     markdown-regex-angle-uri 0 2)))
+        (markdown-wrap-or-insert "<" ">" nil (car bounds) (cdr bounds)))
+    ;; Markup removal, URI at point, or empty markup insertion
+    (if (thing-at-point-looking-at markdown-regex-angle-uri)
+        (markdown-unwrap-thing-at-point nil 0 2)
+      (markdown-wrap-or-insert "<" ">" 'url nil nil))))
+
+(defun markdown-insert-wiki-link ()
+  "Insert a wiki link of the form [[WikiLink]].
+If there is an active region, use the region as the link text.
+If the point is at a word, use the word as the link text.  If
+there is no active region and the point is not at word, simply
+insert link markup."
+  (interactive)
+  (if (markdown-use-region-p)
+      ;; Active region
+      (markdown-wrap-or-insert "[[" "]]" nil (region-beginning) (region-end))
+    ;; Markup removal, wiki link at at point, or empty markup insertion
+    (if (thing-at-point-looking-at markdown-regex-wiki-link)
+        (if (or markdown-wiki-link-alias-first
+                (null (match-string 5)))
+            (markdown-unwrap-thing-at-point nil 1 3)
+          (markdown-unwrap-thing-at-point nil 1 5))
+      (markdown-wrap-or-insert "[[" "]]"))))
+
+(defun markdown-insert-image (&optional arg)
+  "Insert image markup using region or word as alt text if possible.
+If there is an active region, use the region as the alt text.  If the
+point is at a word, use the word as the alt text.  In these cases, the
+point will be left at the position for inserting a URL.  If there is no
+active region and the point is not at word, simply insert image markup and
+place the point in the position to enter alt text.  If ARG is nil, insert
+inline image markup.  Otherwise, insert reference image markup."
+  (interactive "*P")
+  (let ((bounds (if arg
+                    (markdown-wrap-or-insert "![" "][]")
+                  (markdown-wrap-or-insert "![" "]()"))))
+    (when bounds
+      (goto-char (- (cdr bounds) 1)))))
+
+(defun markdown-insert-reference-image ()
+  "Insert reference-style image markup using region or word as alt text.
+Calls `markdown-insert-image' with prefix argument."
+  (interactive)
+  (markdown-insert-image t))
+
+(defun markdown-remove-header ()
+  "Remove header markup if point is at a header.
+Return bounds of remaining header text if a header was removed
+and nil otherwise."
+  (interactive "*")
+  (or (markdown-unwrap-thing-at-point markdown-regex-header-atx 0 2)
+      (markdown-unwrap-thing-at-point markdown-regex-header-setext 0 1)))
+
+(defun markdown-insert-header (&optional level text setext)
+  "Insert or replace header markup.
+The level of the header is specified by LEVEL and header text is
+given by TEXT.  LEVEL must be an integer from 1 and 6, and the
+default value is 1.
+When TEXT is nil, the header text is obtained as follows.
+If there is an active region, it is used as the header text.
+Otherwise, the current line will be used as the header text.
+If there is not an active region and the point is at a header,
+remove the header markup and replace with level N header.
+Otherwise, insert empty header markup and place the cursor in
+between.
+The style of the header will be atx (hash marks) unless
+SETEXT is non-nil, in which case a setext-style (underlined)
+header will be inserted."
+  (interactive "p\nsHeader text: ")
+  (setq level (min (max (or level 1) 1) (if setext 2 6)))
+  ;; Determine header text if not given
+  (when (null text)
+    (if (markdown-use-region-p)
+        ;; Active region
+        (setq text (delete-and-extract-region (region-beginning) (region-end)))
+      ;; No active region
+      (markdown-remove-header)
+      (setq text (delete-and-extract-region
+                  (line-beginning-position) (line-end-position)))
+      (when (and setext (string-match "^[ \t]*$" text))
+        (setq text (read-string "Header text: "))))
+    (setq text (markdown-compress-whitespace-string text)))
+  ;; Insertion with given text
+  (markdown-ensure-blank-line-before)
+  (let (hdr)
+    (cond (setext
+           (setq hdr (make-string (string-width text) (if (= level 2) ?- ?=)))
+           (insert text "\n" hdr))
+          (t
+           (setq hdr (make-string level ?#))
+           (insert hdr " " text)
+           (when (null markdown-asymmetric-header) (insert " " hdr)))))
+  (markdown-ensure-blank-line-after)
+  ;; Leave point at end of text
+  (if setext
+      (backward-char (1+ (string-width text)))
+    (backward-char (1+ level))))
+
+(defun markdown-insert-header-dwim (&optional arg setext)
+  "Insert or replace header markup.
+The level and type of the header are determined automatically by
+the type and level of the previous header, unless a prefix
+argument is given via ARG.
+With a numeric prefix valued 1 to 6, insert a header of the given
+level, with the type being determined automatically (note that
+only level 1 or 2 setext headers are possible).
+
+With a \\[universal-argument] prefix (i.e., when ARG is (4)),
+promote the heading by one level.
+With two \\[universal-argument] prefixes (i.e., when ARG is (16)),
+demote the heading by one level.
+When SETEXT is non-nil, prefer setext-style headers when
+possible (levels one and two).
+
+When there is an active region, use it for the header text.  When
+the point is at an existing header, change the type and level
+according to the rules above.
+Otherwise, if the line is not empty, create a header using the
+text on the current line as the header text.
+Finally, if the point is on a blank line, insert empty header
+markup (atx) or prompt for text (setext).
+See `markdown-insert-header' for more details about how the
+header text is determined."
+  (interactive "*P")
+  (let (level)
+    (save-excursion
+      (when (re-search-backward markdown-regex-header nil t)
+        ;; level of previous header
+        (setq level (markdown-outline-level))
+        ;; match groups 1 and 2 indicate setext headers
+        (setq setext (or setext (match-end 1) (match-end 3)))))
+    ;; check prefix argument
+    (cond
+     ((and (equal arg '(4)) (> level 1)) ;; C-u
+      (cl-decf level))
+     ((and (equal arg '(16)) (< level 6)) ;; C-u C-u
+      (cl-incf level))
+     (arg ;; numeric prefix
+      (setq level (prefix-numeric-value arg))))
+    ;; setext headers must be level one or two
+    (and level (setq setext (and setext (<= level 2))))
+    ;; insert the heading
+    (markdown-insert-header level nil setext)))
+
+(defun markdown-insert-header-setext-dwim (&optional arg)
+  "Insert or replace header markup, with preference for setext.
+See `markdown-insert-header-dwim' for details, including how ARG is handled."
+  (interactive "*P")
+  (markdown-insert-header-dwim arg t))
+
+(defun markdown-insert-header-atx-1 ()
+  "Insert a first level atx-style (hash mark) header.
+See `markdown-insert-header'."
+  (interactive "*")
+  (markdown-insert-header 1 nil nil))
+
+(defun markdown-insert-header-atx-2 ()
+  "Insert a level two atx-style (hash mark) header.
+See `markdown-insert-header'."
+  (interactive "*")
+  (markdown-insert-header 2 nil nil))
+
+(defun markdown-insert-header-atx-3 ()
+  "Insert a level three atx-style (hash mark) header.
+See `markdown-insert-header'."
+  (interactive "*")
+  (markdown-insert-header 3 nil nil))
+
+(defun markdown-insert-header-atx-4 ()
+  "Insert a level four atx-style (hash mark) header.
+See `markdown-insert-header'."
+  (interactive "*")
+  (markdown-insert-header 4 nil nil))
+
+(defun markdown-insert-header-atx-5 ()
+  "Insert a level five atx-style (hash mark) header.
+See `markdown-insert-header'."
+  (interactive "*")
+  (markdown-insert-header 5 nil nil))
+
+(defun markdown-insert-header-atx-6 ()
+  "Insert a sixth level atx-style (hash mark) header.
+See `markdown-insert-header'."
+  (interactive "*")
+  (markdown-insert-header 6 nil nil))
+
+(defun markdown-insert-header-setext-1 ()
+  "Insert a setext-style (underlined) first-level header.
+See `markdown-insert-header'."
+  (interactive "*")
+  (markdown-insert-header 1 nil t))
+
+(defun markdown-insert-header-setext-2 ()
+  "Insert a setext-style (underlined) second-level header.
+See `markdown-insert-header'."
+  (interactive "*")
+  (markdown-insert-header 2 nil t))
+
+(defun markdown-blockquote-indentation (loc)
+  "Return string containing necessary indentation for a blockquote at LOC.
+Also see `markdown-pre-indentation'."
+  (save-excursion
+    (goto-char loc)
+    (let* ((list-level (length (markdown-calculate-list-levels)))
+           (indent ""))
+      (dotimes (count list-level indent)
+        (setq indent (concat indent "    "))))))
+
+(defun markdown-insert-blockquote ()
+  "Start a blockquote section (or blockquote the region).
+If Transient Mark mode is on and a region is active, it is used as
+the blockquote text."
+  (interactive)
+  (if (markdown-use-region-p)
+      (markdown-blockquote-region (region-beginning) (region-end))
+    (markdown-ensure-blank-line-before)
+    (insert (markdown-blockquote-indentation (point)) "> ")
+    (markdown-ensure-blank-line-after)))
+
+(defun markdown-block-region (beg end prefix)
+  "Format the region using a block prefix.
+Arguments BEG and END specify the beginning and end of the
+region.  The characters PREFIX will appear at the beginning
+of each line."
+  (save-excursion
+    (let* ((end-marker (make-marker))
+           (beg-marker (make-marker)))
+      ;; Ensure blank line after and remove extra whitespace
+      (goto-char end)
+      (skip-syntax-backward "-")
+      (set-marker end-marker (point))
+      (delete-horizontal-space)
+      (markdown-ensure-blank-line-after)
+      ;; Ensure blank line before and remove extra whitespace
+      (goto-char beg)
+      (skip-syntax-forward "-")
+      (delete-horizontal-space)
+      (markdown-ensure-blank-line-before)
+      (set-marker beg-marker (point))
+      ;; Insert PREFIX before each line
+      (goto-char beg-marker)
+      (while (and (< (line-beginning-position) end-marker)
+                  (not (eobp)))
+        (insert prefix)
+        (forward-line)))))
+
+(defun markdown-blockquote-region (beg end)
+  "Blockquote the region.
+Arguments BEG and END specify the beginning and end of the region."
+  (interactive "*r")
+  (markdown-block-region
+   beg end (concat (markdown-blockquote-indentation
+                    (max (point-min) (1- beg))) "> ")))
+
+(defun markdown-pre-indentation (loc)
+  "Return string containing necessary whitespace for a pre block at LOC.
+Also see `markdown-blockquote-indentation'."
+  (save-excursion
+    (goto-char loc)
+    (let* ((list-level (length (markdown-calculate-list-levels)))
+           indent)
+      (dotimes (count (1+ list-level) indent)
+        (setq indent (concat indent "    "))))))
+
+(defun markdown-insert-pre ()
+  "Start a preformatted section (or apply to the region).
+If Transient Mark mode is on and a region is active, it is marked
+as preformatted text."
+  (interactive)
+  (if (markdown-use-region-p)
+      (markdown-pre-region (region-beginning) (region-end))
+    (markdown-ensure-blank-line-before)
+    (insert (markdown-pre-indentation (point)))
+    (markdown-ensure-blank-line-after)))
+
+(defun markdown-pre-region (beg end)
+  "Format the region as preformatted text.
+Arguments BEG and END specify the beginning and end of the region."
+  (interactive "*r")
+  (let ((indent (markdown-pre-indentation (max (point-min) (1- beg)))))
+    (markdown-block-region beg end indent)))
+
+(defun markdown-electric-backquote (arg)
+  "Insert a backquote.
+The numeric prefix argument ARG says how many times to repeat the insertion.
+Call `markdown-insert-gfm-code-block' interactively
+if three backquotes inserted at the beginning of line."
+  (interactive "*P")
+  (self-insert-command (prefix-numeric-value arg))
+  (when (and markdown-gfm-use-electric-backquote (looking-back "^```" nil))
+    (replace-match "")
+    (call-interactively #'markdown-insert-gfm-code-block)))
+
+(defconst markdown-gfm-recognized-languages
+  ;; to reproduce/update, evaluate the let-form in
+  ;; scripts/get-recognized-gfm-languages.el. that produces a single long sexp,
+  ;; but with appropriate use of a keyboard macro, indenting and filling it
+  ;; properly is pretty fast.
+  '("ABAP" "AMPL" "ANTLR" "APL" "ASP" "ATS" "ActionScript" "Ada" "Agda" "Alloy"
+    "ApacheConf" "Apex" "AppleScript" "Arc" "Arduino" "AsciiDoc" "AspectJ"
+    "Assembly" "Augeas" "AutoHotkey" "AutoIt" "Awk" "Batchfile" "Befunge"
+    "Bison" "BitBake" "BlitzBasic" "BlitzMax" "Bluespec" "Boo" "Brainfuck"
+    "Brightscript" "Bro" "C" "C++" "C-ObjDump" "CLIPS" "CMake" "COBOL" "CSS"
+    "CartoCSS" "Ceylon" "Chapel" "Charity" "ChucK" "Cirru" "Clarion" "Clean"
+    "Click" "Clojure" "CoffeeScript" "ColdFusion" "Cool" "Coq" "Cpp-ObjDump"
+    "Creole" "Crystal" "Cucumber" "Cuda" "Cycript" "Cython" "D" "D-ObjDump" "DM"
+    "DTrace" "Dart" "Diff" "Dockerfile" "Dogescript" "Dylan" "E" "ECL" "ECLiPSe"
+    "Eagle" "Eiffel" "Elixir" "Elm" "EmberScript" "Erlang" "FLUX" "FORTRAN"
+    "Factor" "Fancy" "Fantom" "Filterscript" "Formatted" "Forth" "FreeMarker"
+    "Frege" "G-code" "GAMS" "GAP" "GAS" "GDScript" "GLSL" "Genshi" "Glyph"
+    "Gnuplot" "Go" "Golo" "Gosu" "Grace" "Gradle" "Groff" "Groovy" "HCL" "HTML"
+    "HTML+Django" "HTML+EEX" "HTML+ERB" "HTML+PHP" "HTTP" "Hack" "Haml"
+    "Handlebars" "Harbour" "Haskell" "Haxe" "Hy" "HyPhy" "IDL" "INI" "Idris"
+    "Io" "Ioke" "Isabelle" "J" "JFlex" "JSON" "JSON5" "JSONLD" "JSONiq" "JSX"
+    "Jade" "Jasmin" "Java" "JavaScript" "Julia" "KRL" "KiCad" "Kit" "Kotlin"
+    "LFE" "LLVM" "LOLCODE" "LSL" "LabVIEW" "Lasso" "Latte" "Lean" "Less" "Lex"
+    "LilyPond" "Limbo" "Liquid" "LiveScript" "Logos" "Logtalk" "LookML"
+    "LoomScript" "Lua" "M" "MAXScript" "MTML" "MUF" "Makefile" "Mako" "Markdown"
+    "Mask" "Mathematica" "Matlab" "Max" "MediaWiki" "Mercury" "Metal" "MiniD"
+    "Mirah" "Modelica" "Modula-2" "Monkey" "Moocode" "MoonScript" "Myghty" "NCL"
+    "NL" "NSIS" "Nemerle" "NetLinx" "NetLinx+ERB" "NetLogo" "NewLisp" "Nginx"
+    "Nimrod" "Ninja" "Nit" "Nix" "Nu" "NumPy" "OCaml" "ObjDump" "Objective-C"
+    "Objective-C++" "Objective-J" "Omgrofl" "Opa" "Opal" "OpenCL" "OpenSCAD"
+    "Org" "Ox" "Oxygene" "Oz" "PAWN" "PHP" "PLSQL" "PLpgSQL" "Pan" "Papyrus"
+    "Parrot" "Pascal" "Perl" "Perl6" "Pickle" "PicoLisp" "PigLatin" "Pike" "Pod"
+    "PogoScript" "Pony" "PostScript" "PowerShell" "Processing" "Prolog" "Puppet"
+    "PureBasic" "PureScript" "Python" "QML" "QMake" "R" "RAML" "RDoc"
+    "REALbasic" "RHTML" "RMarkdown" "Racket" "Rebol" "Red" "Redcode" "Ren'Py"
+    "RenderScript" "RobotFramework" "Rouge" "Ruby" "Rust" "SAS" "SCSS" "SMT"
+    "SPARQL" "SQF" "SQL" "SQLPL" "STON" "SVG" "Sage" "SaltStack" "Sass" "Scala"
+    "Scaml" "Scheme" "Scilab" "Self" "Shell" "ShellSession" "Shen" "Slash"
+    "Slim" "Smali" "Smalltalk" "Smarty" "SourcePawn" "Squirrel" "Stan" "Stata"
+    "Stylus" "SuperCollider" "Swift" "SystemVerilog" "TOML" "TXL" "Tcl" "Tcsh"
+    "TeX" "Tea" "Text" "Textile" "Thrift" "Turing" "Turtle" "Twig" "TypeScript"
+    "UnrealScript" "UrWeb" "VCL" "VHDL" "Vala" "Verilog" "VimL" "Volt" "Vue"
+    "WebIDL" "X10" "XC" "XML" "XPages" "XProc" "XQuery" "XS" "XSLT" "Xojo"
+    "Xtend" "YAML" "Yacc" "Zephir" "Zimpl" "desktop" "eC" "edn" "fish" "mupad"
+    "nesC" "ooc" "reStructuredText" "wisp" "xBase")
+  "Language specifiers recognized by github's syntax highlighting features.")
+
+(defvar markdown-gfm-used-languages nil
+  "Languages used in the current buffer in GFM code blocks, which are not
+already in `markdown-gfm-recognized-languages' or
+`markdown-gfm-additional-languages'.")
+(make-variable-buffer-local 'markdown-gfm-used-languages)
+(defvar markdown-gfm-last-used-language nil
+  "Last language used in the current buffer in GFM code blocks.")
+(make-variable-buffer-local 'markdown-gfm-last-used-language)
+
+(defun markdown-trim-whitespace (str)
+  (markdown-replace-regexp-in-string
+   "\\(?:[[:space:]\r\n]+\\'\\|\\`[[:space:]\r\n]+\\)" "" str))
+
+(defun markdown-clean-language-string (str)
+  (markdown-replace-regexp-in-string
+   "{\\.?\\|}" "" (markdown-trim-whitespace str)))
+
+(defun markdown-validate-language-string (widget)
+  (let ((str (widget-value widget)))
+    (unless (string= str (markdown-clean-language-string str))
+      (widget-put widget :error (format "Invalid language spec: '%s'" str))
+      widget)))
+
+(defun markdown-gfm-get-corpus ()
+  "Create corpus of recognized GFM code block languages for the given buffer."
+  (append markdown-gfm-used-languages
+          markdown-gfm-additional-languages
+          markdown-gfm-recognized-languages))
+
+(defun markdown-add-language-if-new (lang)
+  (let* ((cleaned-lang (markdown-clean-language-string lang))
+         (find-result
+          (cl-find cleaned-lang (markdown-gfm-get-corpus)
+                   :test #'equal)))
+    (setq markdown-gfm-last-used-language cleaned-lang)
+    (unless find-result (push cleaned-lang markdown-gfm-used-languages))))
+
+(defun markdown-insert-gfm-code-block (&optional lang)
+  "Insert GFM code block for language LANG.
+If LANG is nil, the language will be queried from user.  If a
+region is active, wrap this region with the markup instead.  If
+the region boundaries are not on empty lines, these are added
+automatically in order to have the correct markup."
+  (interactive
+   (list (let ((completion-ignore-case nil))
+           (condition-case _err
+               (markdown-clean-language-string
+                (completing-read
+                 (format "Programming language [%s]: "
+                         (or markdown-gfm-last-used-language "none"))
+                 (markdown-gfm-get-corpus)
+                 nil 'confirm nil
+                 'markdown-gfm-language-history
+                 (or markdown-gfm-last-used-language
+                     (car markdown-gfm-additional-languages))))
+             (quit "")))))
+  (unless (string= lang "") (markdown-add-language-if-new lang))
+  (when (> (length lang) 0) (setq lang (concat " " lang)))
+  (if (markdown-use-region-p)
+      (let ((b (region-beginning)) (e (region-end)))
+        (goto-char e)
+        ;; if we're on a blank line, don't newline, otherwise the ```
+        ;; should go on its own line
+        (unless (looking-back "\n" nil)
+          (newline))
+        (insert "```")
+        (markdown-ensure-blank-line-after)
+        (goto-char b)
+        ;; if we're on a blank line, insert the quotes here, otherwise
+        ;; add a new line first
+        (unless (looking-at "\n")
+          (newline)
+          (forward-line -1))
+        (markdown-ensure-blank-line-before)
+        (insert "```" lang))
+    (markdown-ensure-blank-line-before)
+    (insert "```" lang)
+    (newline 2)
+    (insert "```")
+    (markdown-ensure-blank-line-after)
+    (forward-line -1)))
+
+(defun markdown-gfm-parse-buffer-for-languages (&optional buffer)
+  (with-current-buffer (or buffer (current-buffer))
+    (save-excursion
+      (goto-char (point-min))
+      (while (re-search-forward markdown-regex-gfm-code-block nil t)
+        (let ((lang (match-string-no-properties 2)))
+          (when lang (markdown-add-language-if-new lang)))))))
+
+
+;;; Footnotes ======================================================================
+
+(defun markdown-footnote-counter-inc ()
+  "Increment `markdown-footnote-counter' and return the new value."
+  (when (= markdown-footnote-counter 0) ; hasn't been updated in this buffer yet.
+    (save-excursion
+      (goto-char (point-min))
+      (while (re-search-forward (concat "^\\[\\^\\(" markdown-footnote-chars "*?\\)\\]:")
+                                (point-max) t)
+        (let ((fn (string-to-number (match-string 1))))
+          (when (> fn markdown-footnote-counter)
+            (setq markdown-footnote-counter fn))))))
+  (cl-incf markdown-footnote-counter))
+
+(defun markdown-insert-footnote ()
+  "Insert footnote with a new number and move point to footnote definition."
+  (interactive)
+  (let ((fn (markdown-footnote-counter-inc)))
+    (insert (format "[^%d]" fn))
+    (markdown-footnote-text-find-new-location)
+    (markdown-ensure-blank-line-before)
+    (unless (markdown-cur-line-blank-p)
+      (insert "\n"))
+    (insert (format "[^%d]: " fn))
+    (markdown-ensure-blank-line-after)))
+
+(defun markdown-footnote-text-find-new-location ()
+  "Position the cursor at the proper location for a new footnote text."
+  (cond
+   ((eq markdown-footnote-location 'end) (goto-char (point-max)))
+   ((eq markdown-footnote-location 'immediately) (markdown-end-of-block))
+   ((eq markdown-footnote-location 'header) (markdown-end-of-defun))))
+
+(defun markdown-footnote-kill ()
+  "Kill the footnote at point.
+The footnote text is killed (and added to the kill ring), the
+footnote marker is deleted.  Point has to be either at the
+footnote marker or in the footnote text."
+  (interactive)
+  (let ((marker-pos nil)
+        (skip-deleting-marker nil)
+        (starting-footnote-text-positions
+         (markdown-footnote-text-positions)))
+    (when starting-footnote-text-positions
+      ;; We're starting in footnote text, so mark our return position and jump
+      ;; to the marker if possible.
+      (let ((marker-pos (markdown-footnote-find-marker
+                         (cl-first starting-footnote-text-positions))))
+            (if marker-pos
+                (goto-char (1- marker-pos))
+              ;; If there isn't a marker, we still want to kill the text.
+              (setq skip-deleting-marker t))))
+    ;; Either we didn't start in the text, or we started in the text and jumped
+    ;; to the marker. We want to assume we're at the marker now and error if
+    ;; we're not.
+    (unless skip-deleting-marker
+      (let ((marker (markdown-footnote-delete-marker)))
+        (unless marker
+          (error "Not at a footnote"))
+        ;; Even if we knew the text position before, it changed when we deleted
+        ;; the label.
+        (setq marker-pos (cl-second marker))
+        (let ((new-text-pos (markdown-footnote-find-text (cl-first marker))))
+          (unless new-text-pos
+            (error "No text for footnote `%s'" (cl-first marker)))
+          (goto-char new-text-pos))))
+    (let ((pos (markdown-footnote-kill-text)))
+      (goto-char (if starting-footnote-text-positions
+                     pos
+                   marker-pos)))))
+
+(defun markdown-footnote-delete-marker ()
+  "Delete a footnote marker at point.
+Returns a list (ID START) containing the footnote ID and the
+start position of the marker before deletion.  If no footnote
+marker was deleted, this function returns NIL."
+  (let ((marker (markdown-footnote-marker-positions)))
+    (when marker
+      (delete-region (cl-second marker) (cl-third marker))
+      (butlast marker))))
+
+(defun markdown-footnote-kill-text ()
+  "Kill footnote text at point.
+Returns the start position of the footnote text before deletion,
+or NIL if point was not inside a footnote text.
+
+The killed text is placed in the kill ring (without the footnote
+number)."
+  (let ((fn (markdown-footnote-text-positions)))
+    (when fn
+      (let ((text (delete-and-extract-region (cl-second fn) (cl-third fn))))
+        (string-match (concat "\\[\\" (cl-first fn) "\\]:[[:space:]]*\\(\\(.*\n?\\)*\\)") text)
+        (kill-new (match-string 1 text))
+        (when (and (markdown-cur-line-blank-p)
+                   (markdown-prev-line-blank-p)
+                   (not (bobp)))
+          (delete-region (1- (point)) (point)))
+        (cl-second fn)))))
+
+(defun markdown-footnote-goto-text ()
+  "Jump to the text of the footnote at point."
+  (interactive)
+  (let ((fn (car (markdown-footnote-marker-positions))))
+    (unless fn
+      (error "Not at a footnote marker"))
+    (let ((new-pos (markdown-footnote-find-text fn)))
+      (unless new-pos
+        (error "No definition found for footnote `%s'" fn))
+      (goto-char new-pos))))
+
+(defun markdown-footnote-return ()
+  "Return from a footnote to its footnote number in the main text."
+  (interactive)
+  (let ((fn (save-excursion
+              (car (markdown-footnote-text-positions)))))
+    (unless fn
+      (error "Not in a footnote"))
+    (let ((new-pos (markdown-footnote-find-marker fn)))
+      (unless new-pos
+        (error "Footnote marker `%s' not found" fn))
+      (goto-char new-pos))))
+
+(defun markdown-footnote-find-marker (id)
+  "Find the location of the footnote marker with ID.
+The actual buffer position returned is the position directly
+following the marker's closing bracket.  If no marker is found,
+NIL is returned."
+  (save-excursion
+    (goto-char (point-min))
+    (when (re-search-forward (concat "\\[" id "\\]\\([^:]\\|\\'\\)") nil t)
+      (skip-chars-backward "^]")
+      (point))))
+
+(defun markdown-footnote-find-text (id)
+  "Find the location of the text of footnote ID.
+The actual buffer position returned is the position of the first
+character of the text, after the footnote's identifier.  If no
+footnote text is found, NIL is returned."
+  (save-excursion
+    (goto-char (point-min))
+    (when (re-search-forward (concat "^\\[" id "\\]:") nil t)
+      (skip-chars-forward "[ \t]")
+      (point))))
+
+(defun markdown-footnote-marker-positions ()
+  "Return the position and ID of the footnote marker point is on.
+The return value is a list (ID START END).  If point is not on a
+footnote, NIL is returned."
+  ;; first make sure we're at a footnote marker
+  (if (or (looking-back (concat "\\[\\^" markdown-footnote-chars "*\\]?") (line-beginning-position))
+          (looking-at (concat "\\[?\\^" markdown-footnote-chars "*?\\]")))
+      (save-excursion
+        ;; move point between [ and ^:
+        (if (looking-at "\\[")
+            (forward-char 1)
+          (skip-chars-backward "^["))
+        (looking-at (concat "\\(\\^" markdown-footnote-chars "*?\\)\\]"))
+        (list (match-string 1) (1- (match-beginning 1)) (1+ (match-end 1))))))
+
+(defun markdown-footnote-text-positions ()
+  "Return the start and end positions of the footnote text point is in.
+The exact return value is a list of three elements: (ID START END).
+The start position is the position of the opening bracket
+of the footnote id.  The end position is directly after the
+newline that ends the footnote.  If point is not in a footnote,
+NIL is returned instead."
+  (save-excursion
+    (let (result)
+      (move-beginning-of-line 1)
+      ;; Try to find the label. If we haven't found the label and we're at a blank
+      ;; or indented line, back up if possible.
+      (while (and
+              (not (and (looking-at markdown-regex-footnote-definition)
+                        (setq result (list (match-string 1) (point)))))
+              (and (not (bobp))
+                   (or (markdown-cur-line-blank-p)
+                       (>= (markdown-cur-line-indent) 4))))
+        (forward-line -1))
+      (when result
+        ; Advance if there is a next line that is either blank or indented.
+        ; (Need to check if we're on the last line, because
+        ; markdown-next-line-blank-p returns true for last line in buffer.)
+        (while (and (/= (line-end-position) (point-max))
+                    (or (markdown-next-line-blank-p)
+                        (>= (markdown-next-line-indent) 4)))
+          (forward-line))
+        ; Move back while the current line is blank.
+        (while (markdown-cur-line-blank-p)
+          (forward-line -1))
+        ; Advance to capture this line and a single trailing newline (if there
+        ; is one).
+        (forward-line)
+        (append result (list (point)))))))
+
+
+;;; Element Removal ===========================================================
+
+(defun markdown-kill-thing-at-point ()
+  "Kill thing at point and add important text, without markup, to kill ring.
+Possible things to kill include (roughly in order of precedence):
+inline code, headers, horizonal rules, links (add link text to
+kill ring), images (add alt text to kill ring), angle uri, email
+addresses, bold, italics, reference definition (add URI to kill
+ring), footnote markers and text (kill both marker and text, add
+text to kill ring), and list items."
+  (interactive "*")
+  (let (val tmp)
+    (cond
+     ;; Inline code
+     ((markdown-code-at-point-p)
+      (kill-new (match-string 2))
+      (delete-region (match-beginning 0) (match-end 0)))
+     ;; ATX header
+     ((thing-at-point-looking-at markdown-regex-header-atx)
+      (kill-new (match-string 2))
+      (delete-region (match-beginning 0) (match-end 0)))
+     ;; Setext header
+     ((thing-at-point-looking-at markdown-regex-header-setext)
+      (kill-new (match-string 1))
+      (delete-region (match-beginning 0) (match-end 0)))
+     ;; Horizonal rule
+     ((thing-at-point-looking-at markdown-regex-hr)
+      (kill-new (match-string 0))
+      (delete-region (match-beginning 0) (match-end 0)))
+     ;; Inline link or image (add link or alt text to kill ring)
+     ((thing-at-point-looking-at markdown-regex-link-inline)
+      (kill-new (match-string 3))
+      (delete-region (match-beginning 0) (match-end 0)))
+     ;; Reference link or image (add link or alt text to kill ring)
+     ((thing-at-point-looking-at markdown-regex-link-reference)
+      (kill-new (match-string 3))
+      (delete-region (match-beginning 0) (match-end 0)))
+     ;; Angle URI (add URL to kill ring)
+     ((thing-at-point-looking-at markdown-regex-angle-uri)
+      (kill-new (match-string 2))
+      (delete-region (match-beginning 0) (match-end 0)))
+     ;; Email address in angle brackets (add email address to kill ring)
+     ((thing-at-point-looking-at markdown-regex-email)
+      (kill-new (match-string 1))
+      (delete-region (match-beginning 0) (match-end 0)))
+     ;; Wiki link (add alias text to kill ring)
+     ((thing-at-point-looking-at markdown-regex-wiki-link)
+      (kill-new (markdown-wiki-link-alias))
+      (delete-region (match-beginning 1) (match-end 1)))
+     ;; Bold
+     ((thing-at-point-looking-at markdown-regex-bold)
+      (kill-new (match-string 4))
+      (delete-region (match-beginning 2) (match-end 2)))
+     ;; Italics
+     ((thing-at-point-looking-at markdown-regex-italic)
+      (kill-new (match-string 3))
+      (delete-region (match-beginning 1) (match-end 1)))
+     ;; Strikethrough
+     ((thing-at-point-looking-at markdown-regex-strike-through)
+      (kill-new (match-string 4))
+      (delete-region (match-beginning 2) (match-end 2)))
+     ;; Footnote marker (add footnote text to kill ring)
+     ((thing-at-point-looking-at markdown-regex-footnote)
+      (markdown-footnote-kill))
+     ;; Footnote text (add footnote text to kill ring)
+     ((setq val (markdown-footnote-text-positions))
+      (markdown-footnote-kill))
+     ;; Reference definition (add URL to kill ring)
+     ((thing-at-point-looking-at markdown-regex-reference-definition)
+      (kill-new (match-string 5))
+      (delete-region (match-beginning 0) (match-end 0)))
+     ;; List item
+     ((setq val (markdown-cur-list-item-bounds))
+      (kill-new (delete-and-extract-region (cl-first val) (cl-second val))))
+     (t
+      (error "Nothing found at point to kill")))))
+
+
+;;; Indentation ====================================================================
+
+(defun markdown-indent-find-next-position (cur-pos positions)
+  "Return the position after the index of CUR-POS in POSITIONS.
+Positions are calculated by `markdown-calc-indents'."
+  (while (and positions
+              (not (equal cur-pos (car positions))))
+    (setq positions (cdr positions)))
+  (or (cadr positions) 0))
+
+(defun markdown-exdent-find-next-position (cur-pos positions)
+  "Return the maximal element that precedes CUR-POS from POSITIONS.
+Positions are calculated by `markdown-calc-indents'."
+  (let ((result 0))
+    (dolist (i positions)
+      (when (< i cur-pos)
+        (setq result (max result i))))
+    result))
+
+(defun markdown-indent-line ()
+  "Indent the current line using some heuristics.
+If the _previous_ command was either `markdown-enter-key' or
+`markdown-cycle', then we should cycle to the next
+reasonable indentation position.  Otherwise, we could have been
+called directly by `markdown-enter-key', by an initial call of
+`markdown-cycle', or indirectly by `auto-fill-mode'.  In
+these cases, indent to the default position.
+Positions are calculated by `markdown-calc-indents'."
+  (interactive)
+  (let ((positions (markdown-calc-indents))
+        (cur-pos (current-column)))
+    (if (not (equal this-command 'markdown-cycle))
+        (indent-line-to (car positions))
+      (setq positions (sort (delete-dups positions) '<))
+      (indent-line-to
+       (markdown-indent-find-next-position cur-pos positions)))))
+
+(defun markdown-calc-indents ()
+  "Return a list of indentation columns to cycle through.
+The first element in the returned list should be considered the
+default indentation level.  This function does not worry about
+duplicate positions, which are handled up by calling functions."
+  (let (pos prev-line-pos positions)
+
+    ;; Indentation of previous line
+    (setq prev-line-pos (markdown-prev-line-indent))
+    (setq positions (cons prev-line-pos positions))
+
+    ;; Indentation of previous non-list-marker text
+    (when (setq pos (markdown-prev-non-list-indent))
+      (setq positions (cons pos positions)))
+
+    ;; Indentation required for a pre block in current context
+    (setq pos (length (markdown-pre-indentation (point))))
+    (setq positions (cons pos positions))
+
+    ;; Indentation of the previous line + tab-width
+    (if prev-line-pos
+        (setq positions (cons (+ prev-line-pos tab-width) positions))
+      (setq positions (cons tab-width positions)))
+
+    ;; Indentation of the previous line - tab-width
+    (if (and prev-line-pos (> prev-line-pos tab-width))
+        (setq positions (cons (- prev-line-pos tab-width) positions)))
+
+    ;; Indentation of all preceeding list markers (when in a list)
+    (when (setq pos (markdown-calculate-list-levels))
+      (setq positions (append pos positions)))
+
+    ;; First column
+    (setq positions (cons 0 positions))
+
+    ;; Return reversed list
+    (reverse positions)))
+
+(defun markdown-enter-key ()
+  "Handle RET according to to the value of `markdown-indent-on-enter'."
+  (interactive)
+  (newline)
+  (when markdown-indent-on-enter
+    (markdown-indent-line)))
+
+(defun markdown-exdent-or-delete (arg)
+  "Handle BACKSPACE by cycling through indentation points.
+When BACKSPACE is pressed, if there is only whitespace
+before the current point, then exdent the line one level.
+Otherwise, do normal delete by repeating
+`backward-delete-char-untabify' ARG times."
+  (interactive "*p")
+  (let ((cur-pos (current-column))
+        (start-of-indention (save-excursion
+                              (back-to-indentation)
+                              (current-column)))
+        (positions (markdown-calc-indents)))
+    (if (and (> cur-pos 0) (= cur-pos start-of-indention))
+        (indent-line-to (markdown-exdent-find-next-position cur-pos positions))
+      (backward-delete-char-untabify arg))))
+
+(defun markdown-find-leftmost-column (beg end)
+  "Find the leftmost column in the region from BEG to END."
+  (let ((mincol 1000))
+    (save-excursion
+      (goto-char beg)
+      (while (< (point) end)
+        (back-to-indentation)
+        (unless (looking-at "[ \t]*$")
+          (setq mincol (min mincol (current-column))))
+        (forward-line 1)
+        ))
+    mincol))
+
+(defun markdown-indent-region (beg end arg)
+  "Indent the region from BEG to END using some heuristics.
+When ARG is non-nil, exdent the region instead.
+See `markdown-indent-line' and `markdown-indent-line'."
+  (interactive "*r\nP")
+  (let* ((positions (sort (delete-dups (markdown-calc-indents)) '<))
+         (leftmostcol (markdown-find-leftmost-column beg end))
+         (next-pos (if arg
+                       (markdown-exdent-find-next-position leftmostcol positions)
+                     (markdown-indent-find-next-position leftmostcol positions))))
+    (indent-rigidly beg end (- next-pos leftmostcol))
+    (setq deactivate-mark nil)))
+
+(defun markdown-exdent-region (beg end)
+  "Call `markdown-indent-region' on region from BEG to END with prefix."
+  (interactive "*r")
+  (markdown-indent-region (region-beginning) (region-end) t))
+
+
+;;; Markup Completion =========================================================
+
+(defconst markdown-complete-alist
+  '((markdown-regex-header-atx . markdown-complete-atx)
+    (markdown-regex-header-setext . markdown-complete-setext)
+    (markdown-regex-hr . markdown-complete-hr))
+  "Association list of form (regexp . function) for markup completion.")
+
+(defun markdown-incomplete-atx-p ()
+  "Return t if ATX header markup is incomplete and nil otherwise.
+Assumes match data is available for `markdown-regex-header-atx'.
+Checks that the number of trailing hash marks equals the number of leading
+hash marks, that there is only a single space before and after the text,
+and that there is no extraneous whitespace in the text."
+  (save-match-data
+    (or
+     ;; Number of starting and ending hash marks differs
+     (not (= (length (match-string 1)) (length (match-string 3))))
+     ;; When the header text is not empty...
+     (and (> (length (match-string 2)) 0)
+          ;; ...if there are extra leading, trailing, or interior spaces
+          (or (not (= (match-beginning 2) (1+ (match-end 1))))
+              (not (= (match-beginning 3) (1+ (match-end 2))))
+              (string-match "[ \t\n]\\{2\\}" (match-string 2))))
+     ;; When the header text is empty...
+     (and (= (length (match-string 2)) 0)
+          ;; ...if there are too many or too few spaces
+          (not (= (match-beginning 3) (+ (match-end 1) 2)))))))
+
+(defun markdown-complete-atx ()
+  "Complete and normalize ATX headers.
+Add or remove hash marks to the end of the header to match the
+beginning.  Ensure that there is only a single space between hash
+marks and header text.  Removes extraneous whitespace from header text.
+Assumes match data is available for `markdown-regex-header-atx'.
+Return nil if markup was complete and non-nil if markup was completed."
+  (when (markdown-incomplete-atx-p)
+    (let* ((new-marker (make-marker))
+           (new-marker (set-marker new-marker (match-end 2))))
+      ;; Hash marks and spacing at end
+      (goto-char (match-end 2))
+      (delete-region (match-end 2) (match-end 3))
+      (insert " " (match-string 1))
+      ;; Remove extraneous whitespace from title
+      (replace-match (markdown-compress-whitespace-string (match-string 2))
+                     t t nil 2)
+      ;; Spacing at beginning
+      (goto-char (match-end 1))
+      (delete-region (match-end 1) (match-beginning 2))
+      (insert " ")
+      ;; Leave point at end of text
+      (goto-char new-marker))))
+
+(defun markdown-incomplete-setext-p ()
+  "Return t if setext header markup is incomplete and nil otherwise.
+Assumes match data is available for `markdown-regex-header-setext'.
+Checks that length of underline matches text and that there is no
+extraneous whitespace in the text."
+  (save-match-data
+    (or (not (= (length (match-string 1)) (length (match-string 2))))
+        (string-match "[ \t\n]\\{2\\}" (match-string 1)))))
+
+(defun markdown-complete-setext ()
+  "Complete and normalize setext headers.
+Add or remove underline characters to match length of header
+text.  Removes extraneous whitespace from header text.  Assumes
+match data is available for `markdown-regex-header-setext'.
+Return nil if markup was complete and non-nil if markup was completed."
+  (when (markdown-incomplete-setext-p)
+    (let* ((text (markdown-compress-whitespace-string (match-string 1)))
+           (char (char-after (match-beginning 2)))
+           (level (if (char-equal char ?-) 2 1)))
+      (goto-char (match-beginning 0))
+      (delete-region (match-beginning 0) (match-end 0))
+      (markdown-insert-header level text t)
+      t)))
+
+(defun markdown-incomplete-hr-p ()
+  "Return non-nil if hr is not in `markdown-hr-strings' and nil otherwise.
+Assumes match data is available for `markdown-regex-hr'."
+  (not (member (match-string 0) markdown-hr-strings)))
+
+(defun markdown-complete-hr ()
+  "Complete horizontal rules.
+If horizontal rule string is a member of `markdown-hr-strings',
+do nothing.  Otherwise, replace with the car of
+`markdown-hr-strings'.
+Assumes match data is available for `markdown-regex-hr'.
+Return nil if markup was complete and non-nil if markup was completed."
+  (when (markdown-incomplete-hr-p)
+    (replace-match (car markdown-hr-strings))
+    t))
+
+(defun markdown-complete ()
+  "Complete markup of object near point or in region when active.
+Handle all objects in `markdown-complete-alist', in order.
+See `markdown-complete-at-point' and `markdown-complete-region'."
+  (interactive "*")
+  (if (markdown-use-region-p)
+      (markdown-complete-region (region-beginning) (region-end))
+    (markdown-complete-at-point)))
+
+(defun markdown-complete-at-point ()
+  "Complete markup of object near point.
+Handle all elements of `markdown-complete-alist' in order."
+  (interactive "*")
+  (let ((list markdown-complete-alist) found changed)
+    (while list
+      (let ((regexp (eval (caar list)))
+            (function (cdar list)))
+        (setq list (cdr list))
+        (when (thing-at-point-looking-at regexp)
+          (setq found t)
+          (setq changed (funcall function))
+          (setq list nil))))
+    (if found
+        (or changed (error "Markup at point is complete"))
+      (error "Nothing to complete at point"))))
+
+(defun markdown-complete-region (beg end)
+  "Complete markup of objects in region from BEG to END.
+Handle all objects in `markdown-complete-alist', in order.  Each
+match is checked to ensure that a previous regexp does not also
+match."
+  (interactive "*r")
+  (let ((end-marker (set-marker (make-marker) end))
+        previous)
+    (dolist (element markdown-complete-alist)
+      (let ((regexp (eval (car element)))
+            (function (cdr element)))
+        (goto-char beg)
+        (while (re-search-forward regexp end-marker 'limit)
+          (when (match-string 0)
+            ;; Make sure this is not a match for any of the preceding regexps.
+            ;; This prevents mistaking an HR for a Setext subheading.
+            (let (match)
+              (save-match-data
+                (dolist (prev-regexp previous)
+                  (or match (setq match (looking-back prev-regexp nil)))))
+              (unless match
+                (save-excursion (funcall function))))))
+        (add-to-list 'previous regexp)))))
+
+(defun markdown-complete-buffer ()
+  "Complete markup for all objects in the current buffer."
+  (interactive "*")
+  (markdown-complete-region (point-min) (point-max)))
+
+
+;;; Markup Cycling ============================================================
+
+(defun markdown-cycle-atx (arg &optional remove)
+  "Cycle ATX header markup.
+Promote header (decrease level) when ARG is 1 and demote
+header (increase level) if arg is -1.  When REMOVE is non-nil,
+remove the header when the level reaches zero and stop cycling
+when it reaches six.  Otherwise, perform a proper cycling through
+levels one through six.  Assumes match data is available for
+`markdown-regex-header-atx'."
+  (let* ((old-level (length (match-string 1)))
+         (new-level (+ old-level arg))
+         (text (match-string 2)))
+    (when (not remove)
+      (setq new-level (% new-level 6))
+      (setq new-level (cond ((= new-level 0) 6)
+                            ((< new-level 0) (+ new-level 6))
+                            (t new-level))))
+    (cond
+     ((= new-level 0)
+      (markdown-unwrap-thing-at-point nil 0 2))
+     ((<= new-level 6)
+      (goto-char (match-beginning 0))
+      (delete-region (match-beginning 0) (match-end 0))
+      (markdown-insert-header new-level text nil)))))
+
+(defun markdown-cycle-setext (arg &optional remove)
+  "Cycle setext header markup.
+Promote header (increase level) when ARG is 1 and demote
+header (decrease level or remove) if arg is -1.  When demoting a
+level-two setext header, replace with a level-three atx header.
+When REMOVE is non-nil, remove the header when the level reaches
+zero.  Otherwise, cycle back to a level six atx header.  Assumes
+match data is available for `markdown-regex-header-setext'."
+  (let* ((char (char-after (match-beginning 2)))
+         (old-level (if (char-equal char ?=) 1 2))
+         (new-level (+ old-level arg))
+         (text (match-string 1)))
+    (when (and (not remove) (= new-level 0))
+      (setq new-level 6))
+    (cond
+     ((= new-level 0)
+      (markdown-unwrap-thing-at-point nil 0 1))
+     ((<= new-level 2)
+      (markdown-insert-header new-level nil t))
+     ((<= new-level 6)
+      (markdown-insert-header new-level nil nil)))))
+
+(defun markdown-cycle-hr (arg &optional remove)
+  "Cycle string used for horizontal rule from `markdown-hr-strings'.
+When ARG is 1, cycle forward (demote), and when ARG is -1, cycle
+backwards (promote).  When REMOVE is non-nil, remove the hr instead
+of cycling when the end of the list is reached.
+Assumes match data is available for `markdown-regex-hr'."
+  (let* ((strings (if (= arg -1)
+                      (reverse markdown-hr-strings)
+                    markdown-hr-strings))
+         (tail (member (match-string 0) strings))
+         (new (or (cadr tail)
+                  (if remove
+                      (if (= arg 1)
+                          ""
+                        (car tail))
+                    (car strings)))))
+    (replace-match new)))
+
+(defun markdown-cycle-bold ()
+  "Cycle bold markup between underscores and asterisks.
+Assumes match data is available for `markdown-regex-bold'."
+  (save-excursion
+    (let* ((old-delim (match-string 3))
+           (new-delim (if (string-equal old-delim "**") "__" "**")))
+      (replace-match new-delim t t nil 3)
+      (replace-match new-delim t t nil 5))))
+
+(defun markdown-cycle-italic ()
+  "Cycle italic markup between underscores and asterisks.
+Assumes match data is available for `markdown-regex-italic'."
+  (save-excursion
+    (let* ((old-delim (match-string 2))
+           (new-delim (if (string-equal old-delim "*") "_" "*")))
+      (replace-match new-delim t t nil 2)
+      (replace-match new-delim t t nil 4))))
+
+
+;;; Keymap ====================================================================
+
+(defvar markdown-mode-map
+  (let ((map (make-keymap)))
+    ;; Element insertion
+    (define-key map "\C-c\C-al" 'markdown-insert-link)
+    (define-key map "\C-c\C-aL" 'markdown-insert-reference-link-dwim)
+    (define-key map "\C-c\C-au" 'markdown-insert-uri)
+    (define-key map "\C-c\C-af" 'markdown-insert-footnote)
+    (define-key map "\C-c\C-aw" 'markdown-insert-wiki-link)
+    (define-key map "\C-c\C-ii" 'markdown-insert-image)
+    (define-key map "\C-c\C-iI" 'markdown-insert-reference-image)
+    (define-key map "\C-c\C-th" 'markdown-insert-header-dwim)
+    (define-key map "\C-c\C-tH" 'markdown-insert-header-setext-dwim)
+    (define-key map "\C-c\C-t1" 'markdown-insert-header-atx-1)
+    (define-key map "\C-c\C-t2" 'markdown-insert-header-atx-2)
+    (define-key map "\C-c\C-t3" 'markdown-insert-header-atx-3)
+    (define-key map "\C-c\C-t4" 'markdown-insert-header-atx-4)
+    (define-key map "\C-c\C-t5" 'markdown-insert-header-atx-5)
+    (define-key map "\C-c\C-t6" 'markdown-insert-header-atx-6)
+    (define-key map "\C-c\C-t!" 'markdown-insert-header-setext-1)
+    (define-key map "\C-c\C-t@" 'markdown-insert-header-setext-2)
+    (define-key map "\C-c\C-ss" 'markdown-insert-bold)
+    (define-key map "\C-c\C-se" 'markdown-insert-italic)
+    (define-key map "\C-c\C-sc" 'markdown-insert-code)
+    (define-key map "\C-c\C-sb" 'markdown-insert-blockquote)
+    (define-key map "\C-c\C-s\C-b" 'markdown-blockquote-region)
+    (define-key map "\C-c\C-sp" 'markdown-insert-pre)
+    (define-key map "\C-c\C-s\C-p" 'markdown-pre-region)
+    (define-key map "\C-c\C-sP" 'markdown-insert-gfm-code-block)
+    (define-key map "\C-c-" 'markdown-insert-hr)
+    ;; Element insertion (deprecated)
+    (define-key map "\C-c\C-ar" 'markdown-insert-reference-link-dwim)
+    (define-key map "\C-c\C-tt" 'markdown-insert-header-setext-1)
+    (define-key map "\C-c\C-ts" 'markdown-insert-header-setext-2)
+    ;; Element removal
+    (define-key map (kbd "C-c C-k") 'markdown-kill-thing-at-point)
+    ;; Promotion, Demotion, Completion, and Cycling
+    (define-key map (kbd "C-c C--") 'markdown-promote)
+    (define-key map (kbd "C-c C-=") 'markdown-demote)
+    (define-key map (kbd "C-c C-]") 'markdown-complete)
+    ;; Following and Jumping
+    (define-key map (kbd "C-c C-o") 'markdown-follow-thing-at-point)
+    (define-key map (kbd "C-c C-j") 'markdown-jump)
+    ;; Indentation
+    (define-key map (kbd "C-m") 'markdown-enter-key)
+    (define-key map (kbd "DEL") 'markdown-exdent-or-delete)
+    (define-key map (kbd "C-c >") 'markdown-indent-region)
+    (define-key map (kbd "C-c <") 'markdown-exdent-region)
+    ;; Visibility cycling
+    (define-key map (kbd "TAB") 'markdown-cycle)
+    (define-key map (kbd "<S-iso-lefttab>") 'markdown-shifttab)
+    (define-key map (kbd "<S-tab>")  'markdown-shifttab)
+    (define-key map (kbd "<backtab>") 'markdown-shifttab)
+    ;; Header navigation
+    (define-key map (kbd "C-c C-n") 'markdown-next-visible-heading)
+    (define-key map (kbd "C-c C-p") 'markdown-previous-visible-heading)
+    (define-key map (kbd "C-c C-f") 'markdown-forward-same-level)
+    (define-key map (kbd "C-c C-b") 'markdown-backward-same-level)
+    (define-key map (kbd "C-c C-u") 'markdown-up-heading)
+    ;; Buffer-wide commands
+    (define-key map (kbd "C-c C-c m") 'markdown-other-window)
+    (define-key map (kbd "C-c C-c p") 'markdown-preview)
+    (define-key map (kbd "C-c C-c e") 'markdown-export)
+    (define-key map (kbd "C-c C-c v") 'markdown-export-and-preview)
+    (define-key map (kbd "C-c C-c o") 'markdown-open)
+    (define-key map (kbd "C-c C-c l") 'markdown-live-preview-mode)
+    (define-key map (kbd "C-c C-c w") 'markdown-kill-ring-save)
+    (define-key map (kbd "C-c C-c c") 'markdown-check-refs)
+    (define-key map (kbd "C-c C-c n") 'markdown-cleanup-list-numbers)
+    (define-key map (kbd "C-c C-c ]") 'markdown-complete-buffer)
+    ;; List editing
+    (define-key map (kbd "M-<up>") 'markdown-move-up)
+    (define-key map (kbd "M-<down>") 'markdown-move-down)
+    (define-key map (kbd "M-<left>") 'markdown-promote)
+    (define-key map (kbd "M-<right>") 'markdown-demote)
+    (define-key map (kbd "M-<return>") 'markdown-insert-list-item)
+    ;; Subtree editing
+    (define-key map (kbd "M-S-<up>") 'markdown-move-subtree-up)
+    (define-key map (kbd "M-S-<down>") 'markdown-move-subtree-down)
+    (define-key map (kbd "M-S-<left>") 'markdown-promote-subtree)
+    (define-key map (kbd "M-S-<right>") 'markdown-demote-subtree)
+    ;; Movement
+    (define-key map (kbd "M-{") 'markdown-backward-paragraph)
+    (define-key map (kbd "M-}") 'markdown-forward-paragraph)
+    (define-key map (kbd "M-n") 'markdown-next-link)
+    (define-key map (kbd "M-p") 'markdown-previous-link)
+    ;; Alternative keys (in case of problems with the arrow keys)
+    (define-key map (kbd "C-c C-x u") 'markdown-move-up)
+    (define-key map (kbd "C-c C-x d") 'markdown-move-down)
+    (define-key map (kbd "C-c C-x l") 'markdown-promote)
+    (define-key map (kbd "C-c C-x r") 'markdown-demote)
+    (define-key map (kbd "C-c C-x m") 'markdown-insert-list-item)
+    map)
+  "Keymap for Markdown major mode.")
+
+(defvar gfm-mode-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map markdown-mode-map)
+    (define-key map (kbd "C-c C-s d") 'markdown-insert-strike-through)
+    (define-key map "`" 'markdown-electric-backquote)
+    map)
+  "Keymap for `gfm-mode'.
+See also `markdown-mode-map'.")
+
+
+;;; Menu ==================================================================
+
+(easy-menu-define markdown-mode-menu markdown-mode-map
+  "Menu for Markdown mode"
+  '("Markdown"
+    ("Show/Hide"
+     ["Cycle visibility" markdown-cycle (markdown-on-heading-p)]
+     ["Cycle global visibility" markdown-shifttab])
+    "---"
+    ["Compile" markdown-other-window]
+    ["Preview" markdown-preview]
+    ["Export" markdown-export]
+    ["Export & View" markdown-export-and-preview]
+    ["Open" markdown-open]
+    ["Live Export" markdown-live-preview-mode
+     :style toggle :selected markdown-live-preview-mode]
+    ["Kill ring save" markdown-kill-ring-save]
+    "---"
+    ("Headings"
+     ["Automatic" markdown-insert-header-dwim]
+     ["Automatic (prefer setext)" markdown-insert-header-setext-dwim]
+     "---"
+     ["First level setext" markdown-insert-header-setext-1]
+     ["Second level setext" markdown-insert-header-setext-2]
+     "---"
+     ["First level atx" markdown-insert-header-atx-1]
+     ["Second level atx" markdown-insert-header-atx-2]
+     ["Third level atx" markdown-insert-header-atx-3]
+     ["Fourth level atx" markdown-insert-header-atx-4]
+     ["Fifth level atx" markdown-insert-header-atx-5]
+     ["Sixth level atx" markdown-insert-header-atx-6])
+    "---"
+    ["Bold" markdown-insert-bold]
+    ["Italic" markdown-insert-italic]
+    ["Strikethrough" markdown-insert-strike-through]
+    ["Blockquote" markdown-insert-blockquote]
+    ["Preformatted" markdown-insert-pre]
+    ["Code" markdown-insert-code]
+    "---"
+    ["Insert inline link" markdown-insert-link]
+    ["Insert reference link" markdown-insert-reference-link-dwim]
+    ["Insert URL" markdown-insert-uri]
+    ["Insert inline image" markdown-insert-image]
+    ["Insert reference image" markdown-insert-reference-image]
+    ["Insert list item" markdown-insert-list-item]
+    ["Insert horizontal rule" markdown-insert-hr]
+    ["Insert footnote" markdown-insert-footnote]
+    ["Kill element" markdown-kill-thing-at-point]
+    "---"
+    ["Jump" markdown-jump]
+    ["Follow link" markdown-follow-thing-at-point]
+    ("Outline"
+     ["Next visible heading" markdown-next-visible-heading]
+     ["Previous visible heading" markdown-previous-visible-heading]
+     ["Forward same level" markdown-forward-same-level]
+     ["Backward same level" markdown-backward-same-level]
+     ["Up to parent heading" markdown-up-heading])
+    "---"
+    ("Completion and Cycling"
+     ["Complete" markdown-complete]
+     ["Promote" markdown-promote]
+     ["Demote" markdown-demote])
+    ("List editing"
+     ["Indent list item" markdown-demote]
+     ["Exdent list item" markdown-promote])
+    ("Region shifting"
+     ["Indent region" markdown-indent-region]
+     ["Exdent region" markdown-exdent-region])
+    "---"
+    ["Check references" markdown-check-refs]
+    ["Clean up list numbering" markdown-cleanup-list-numbers]
+    ["Complete markup" markdown-complete-buffer]
+    "---"
+    ["Version" markdown-show-version]
+    ))
+
+
+;;; imenu =====================================================================
+
+(defun markdown-imenu-create-index ()
+  "Create and return an imenu index alist for the current buffer.
+See `imenu-create-index-function' and `imenu--index-alist' for details."
+  (let* ((root '(nil . nil))
+         cur-alist
+         (cur-level 0)
+         (empty-heading "-")
+         (self-heading ".")
+         hashes pos level heading)
+    (save-excursion
+      (goto-char (point-min))
+      (while (re-search-forward markdown-regex-header (point-max) t)
+        (unless (markdown-code-block-at-point)
+          (cond
+           ((setq heading (match-string-no-properties 1))
+            (setq pos (match-beginning 1)
+                  level 1))
+           ((setq heading (match-string-no-properties 3))
+            (setq pos (match-beginning 3)
+                  level 2))
+           ((setq hashes (match-string-no-properties 5))
+            (setq heading (match-string-no-properties 6)
+                  pos (match-beginning 5)
+                  level (length hashes))))
+          (let ((alist (list (cons heading pos))))
+            (cond
+             ((= cur-level level)       ; new sibling
+              (setcdr cur-alist alist)
+              (setq cur-alist alist))
+             ((< cur-level level)       ; first child
+              (dotimes (i (- level cur-level 1))
+                (setq alist (list (cons empty-heading alist))))
+              (if cur-alist
+                  (let* ((parent (car cur-alist))
+                         (self-pos (cdr parent)))
+                    (setcdr parent (cons (cons self-heading self-pos) alist)))
+                (setcdr root alist))    ; primogenitor
+              (setq cur-alist alist)
+              (setq cur-level level))
+             (t                         ; new sibling of an ancestor
+              (let ((sibling-alist (last (cdr root))))
+                (dotimes (i (1- level))
+                  (setq sibling-alist (last (cdar sibling-alist))))
+                (setcdr sibling-alist alist)
+                (setq cur-alist alist))
+              (setq cur-level level))))))
+      (cdr root))))
+
+
+;;; References ================================================================
+
+(defun markdown-insert-reference-definition (ref &optional buffer)
+  "Add blank REF definition to the end of BUFFER.
+REF is a Markdown reference without the square brackets."
+  (or buffer (setq buffer (current-buffer)))
+  (with-current-buffer buffer
+    (goto-char (point-max))
+    (indent-new-comment-line)
+    (insert (concat "[" ref "]: "))))
+
+(defun markdown-reference-goto-definition ()
+  "Jump to the definition of the reference at point or create it."
+  (interactive)
+  (when (thing-at-point-looking-at markdown-regex-link-reference)
+    (let* ((text (match-string-no-properties 3))
+           (reference (match-string-no-properties 6))
+           (target (downcase (if (string= reference "") text reference)))
+           (loc (cadr (markdown-reference-definition target))))
+      (if loc
+          (goto-char loc)
+        (markdown-insert-reference-definition target (current-buffer))))))
+
+(defun markdown-reference-find-links (reference)
+  "Return a list of all links for REFERENCE.
+REFERENCE should not include the surrounding square brackets.
+Elements of the list have the form (text start line), where
+text is the link text, start is the location at the beginning of
+the link, and line is the line number on which the link appears."
+  (let* ((ref-quote (regexp-quote reference))
+         (regexp (format "!?\\(?:\\[\\(%s\\)\\][ ]?\\[\\]\\|\\[\\([^]]+?\\)\\][ ]?\\[%s\\]\\)"
+                         ref-quote ref-quote))
+         links)
+    (save-excursion
+      (goto-char (point-min))
+      (while (re-search-forward regexp nil t)
+        (let* ((text (or (match-string-no-properties 1)
+                         (match-string-no-properties 2)))
+               (start (match-beginning 0))
+               (line (markdown-line-number-at-pos)))
+          (add-to-list 'links (list text start line)))))
+    links))
+
+(defun markdown-get-undefined-refs ()
+  "Return a list of undefined Markdown references.
+Result is an alist of pairs (reference . occurrences), where
+occurrences is itself another alist of pairs (label . line-number).
+For example, an alist corresponding to [Nice editor][Emacs] at line 12,
+\[GNU Emacs][Emacs] at line 45 and [manual][elisp] at line 127 is
+\((\"emacs\" (\"Nice editor\" . 12) (\"GNU Emacs\" . 45)) (\"elisp\" (\"manual\" . 127)))."
+  (let ((missing))
+    (save-excursion
+      (goto-char (point-min))
+      (while
+          (re-search-forward markdown-regex-link-reference nil t)
+        (let* ((text (match-string-no-properties 3))
+               (reference (match-string-no-properties 6))
+               (target (downcase (if (string= reference "") text reference))))
+          (unless (markdown-reference-definition target)
+            (let ((entry (assoc target missing)))
+              (if (not entry)
+                  (add-to-list 'missing (cons target
+                                              (list (cons text (markdown-line-number-at-pos)))) t)
+                (setcdr entry
+                        (append (cdr entry) (list (cons text (markdown-line-number-at-pos))))))))))
+      missing)))
+
+(defconst markdown-reference-check-buffer
+  "*Undefined references for %buffer%*"
+  "Pattern for name of buffer for listing undefined references.
+The string %buffer% will be replaced by the corresponding
+`markdown-mode' buffer name.")
+
+(defun markdown-reference-check-buffer (&optional buffer-name)
+  "Name and return buffer for reference checking.
+BUFFER-NAME is the name of the main buffer being visited."
+  (or buffer-name (setq buffer-name (buffer-name)))
+  (let ((refbuf (get-buffer-create (markdown-replace-regexp-in-string
+                                    "%buffer%" buffer-name
+                                    markdown-reference-check-buffer))))
+    (with-current-buffer refbuf
+      (when view-mode
+        (View-exit-and-edit))
+      (use-local-map button-buffer-map)
+      (erase-buffer))
+    refbuf))
+
+(defconst markdown-reference-links-buffer
+  "*Reference links for %buffer%*"
+  "Pattern for name of buffer for listing references.
+The string %buffer% will be replaced by the corresponding buffer name.")
+
+(defun markdown-reference-links-buffer (&optional buffer-name)
+  "Name, setup, and return a buffer for listing links.
+BUFFER-NAME is the name of the main buffer being visited."
+  (or buffer-name (setq buffer-name (buffer-name)))
+  (let ((linkbuf (get-buffer-create (markdown-replace-regexp-in-string
+                                     "%buffer%" buffer-name
+                                     markdown-reference-links-buffer))))
+    (with-current-buffer linkbuf
+      (when view-mode
+        (View-exit-and-edit))
+      (use-local-map button-buffer-map)
+      (erase-buffer))
+    linkbuf))
+
+(when (markdown-use-buttons-p)
+  ;; Add an empty Markdown reference definition to the end of buffer
+  ;; specified in the 'target-buffer property.  The reference name is
+  ;; the button's label.
+  (define-button-type 'markdown-undefined-reference-button
+    'help-echo "mouse-1, RET: create definition for undefined reference"
+    'follow-link t
+    'face 'bold
+    'action (lambda (b)
+              (let ((buffer (button-get b 'target-buffer)))
+                (markdown-insert-reference-definition (button-label b) buffer)
+                (switch-to-buffer-other-window buffer)
+                (goto-char (point-max))
+                (markdown-check-refs t))))
+
+  ;; Jump to line in buffer specified by 'target-buffer property.
+  ;; Line number is button's 'line property.
+  (define-button-type 'markdown-goto-line-button
+    'help-echo "mouse-1, RET: go to line"
+    'follow-link t
+    'face 'italic
+    'action (lambda (b)
+              (message (button-get b 'buffer))
+              (switch-to-buffer-other-window (button-get b 'target-buffer))
+              ;; use call-interactively to silence compiler
+              (let ((current-prefix-arg (button-get b 'target-line)))
+                (call-interactively 'goto-line))))
+
+  ;; Jumps to a particular link at location given by 'target-char
+  ;; property in buffer given by 'target-buffer property.
+  (define-button-type 'markdown-link-button
+    'help-echo "mouse-1, RET: jump to location of link"
+    'follow-link t
+    'face 'bold
+    'action (lambda (b)
+              (let ((target (button-get b 'target-buffer))
+                    (loc (button-get b 'target-char)))
+                (kill-buffer-and-window)
+                (switch-to-buffer target)
+                (goto-char loc)))))
+
+(defun markdown-insert-undefined-reference-button (reference oldbuf)
+  "Insert a button for creating REFERENCE in buffer OLDBUF.
+REFERENCE should be a list of the form (reference . occurrences),
+as by `markdown-get-undefined-refs'."
+  (let ((label (car reference)))
+    (if (markdown-use-buttons-p)
+        ;; Create a reference button in Emacs 22
+        (insert-button label
+                       :type 'markdown-undefined-reference-button
+                       'target-buffer oldbuf)
+      ;; Insert reference as text in Emacs < 22
+      (insert label))
+    (insert " (")
+    (dolist (occurrence (cdr reference))
+      (let ((line (cdr occurrence)))
+        (if (markdown-use-buttons-p)
+            ;; Create a line number button in Emacs 22
+            (insert-button (number-to-string line)
+                           :type 'markdown-goto-line-button
+                           'target-buffer oldbuf
+                           'target-line line)
+          ;; Insert line number as text in Emacs < 22
+          (insert (number-to-string line)))
+        (insert " ")))
+    (delete-char -1)
+    (insert ")")
+    (newline)))
+
+(defun markdown-insert-link-button (link oldbuf)
+  "Insert a button for jumping to LINK in buffer OLDBUF.
+LINK should be a list of the form (text char line) containing
+the link text, location, and line number."
+  (let ((label (cl-first link))
+        (char (cl-second link))
+        (line (cl-third link)))
+    (if (markdown-use-buttons-p)
+        ;; Create a reference button in Emacs 22
+        (insert-button label
+                       :type 'markdown-link-button
+                       'target-buffer oldbuf
+                       'target-char char)
+      ;; Insert reference as text in Emacs < 22
+      (insert label))
+    (insert (format " (line %d)\n" line))))
+
+(defun markdown-reference-goto-link (&optional reference)
+  "Jump to the location of the first use of REFERENCE."
+  (interactive)
+  (unless reference
+    (if (thing-at-point-looking-at markdown-regex-reference-definition)
+        (setq reference (match-string-no-properties 2))
+      (error "No reference definition at point")))
+  (let ((links (markdown-reference-find-links reference)))
+    (cond ((= (length links) 1)
+           (goto-char (cadr (car links))))
+          ((> (length links) 1)
+           (let ((oldbuf (current-buffer))
+                 (linkbuf (markdown-reference-links-buffer)))
+             (with-current-buffer linkbuf
+               (insert "Links using reference " reference ":\n\n")
+               (dolist (link (reverse links))
+                 (markdown-insert-link-button link oldbuf)))
+             (view-buffer-other-window linkbuf)
+             (goto-char (point-min))
+             (forward-line 2)))
+          (t
+           (error "No links for reference %s" reference)))))
+
+(defun markdown-check-refs (&optional silent)
+  "Show all undefined Markdown references in current `markdown-mode' buffer.
+If SILENT is non-nil, do not message anything when no undefined
+references found.
+Links which have empty reference definitions are considered to be
+defined."
+  (interactive "P")
+  (when (not (eq major-mode 'markdown-mode))
+    (error "Not available in current mode"))
+  (let ((oldbuf (current-buffer))
+        (refs (markdown-get-undefined-refs))
+        (refbuf (markdown-reference-check-buffer)))
+    (if (null refs)
+        (progn
+          (when (not silent)
+            (message "No undefined references found"))
+          (kill-buffer refbuf))
+      (with-current-buffer refbuf
+        (insert "The following references are undefined:\n\n")
+        (dolist (ref refs)
+          (markdown-insert-undefined-reference-button ref oldbuf))
+        (view-buffer-other-window refbuf)
+        (goto-char (point-min))
+        (forward-line 2)))))
+
+
+;;; Lists =====================================================================
+
+(defun markdown-insert-list-item (&optional arg)
+  "Insert a new list item.
+If the point is inside unordered list, insert a bullet mark.  If
+the point is inside ordered list, insert the next number followed
+by a period.  Use the previous list item to determine the amount
+of whitespace to place before and after list markers.
+
+With a \\[universal-argument] prefix (i.e., when ARG is (4)),
+decrease the indentation by one level.
+
+With two \\[universal-argument] prefixes (i.e., when ARG is (16)),
+increase the indentation by one level."
+  (interactive "p")
+  (let (bounds cur-indent marker indent new-indent new-loc)
+    (save-match-data
+      ;; Look for a list item on current or previous non-blank line
+      (save-excursion
+        (while (and (not (setq bounds (markdown-cur-list-item-bounds)))
+                    (not (bobp))
+                    (markdown-cur-line-blank-p))
+          (forward-line -1)))
+      (when bounds
+        (cond ((save-excursion
+                 (skip-chars-backward " \t")
+                 (looking-at markdown-regex-list))
+               (beginning-of-line)
+               (insert "\n")
+               (forward-line -1))
+              ((not (markdown-cur-line-blank-p))
+               (newline)))
+        (setq new-loc (point)))
+      ;; Look ahead for a list item on next non-blank line
+      (unless bounds
+        (save-excursion
+          (while (and (null bounds)
+                      (not (eobp))
+                      (markdown-cur-line-blank-p))
+            (forward-line)
+            (setq bounds (markdown-cur-list-item-bounds))))
+        (when bounds
+          (setq new-loc (point))
+          (unless (markdown-cur-line-blank-p)
+            (newline))))
+      (if (not bounds)
+          ;; When not in a list, start a new unordered one
+          (progn
+            (unless (markdown-cur-line-blank-p)
+              (insert "\n"))
+            (insert markdown-unordered-list-item-prefix))
+        ;; Compute indentation and marker for new list item
+        (setq cur-indent (nth 2 bounds))
+        (setq marker (nth 4 bounds))
+        (cond
+         ;; Dedent: decrement indentation, find previous marker.
+         ((= arg 4)
+          (setq indent (max (- cur-indent 4) 0))
+          (let ((prev-bounds
+                 (save-excursion
+                   (when (markdown-prev-list-item (- (nth 3 bounds) 1))
+                     (markdown-cur-list-item-bounds)))))
+            (when prev-bounds
+              (setq marker (nth 4 prev-bounds)))))
+         ;; Indent: increment indentation by 4, use same marker.
+         ((= arg 16) (setq indent (+ cur-indent 4)))
+         ;; Same level: keep current indentation and marker.
+         (t (setq indent cur-indent)))
+        (setq new-indent (make-string indent 32))
+        (goto-char new-loc)
+        (cond
+         ;; Ordered list
+         ((string-match "[0-9]" marker)
+          (if (= arg 16) ;; starting a new column indented one more level
+              (insert (concat new-indent "1. "))
+            ;; travel up to the last item and pick the correct number.  If
+            ;; the argument was nil, "new-indent = cur-indent" is the same,
+            ;; so we don't need special treatment. Neat.
+            (save-excursion
+              (while (and (not (looking-at (concat new-indent "\\([0-9]+\\)\\(\\.[ \t]*\\)")))
+                          (>= (forward-line -1) 0))))
+            (let* ((old-prefix (match-string 1))
+                   (old-spacing (match-string 2))
+                   (new-prefix (if old-prefix
+                                   (int-to-string (1+ (string-to-number old-prefix)))
+                                 "1"))
+                   (space-adjust (- (length old-prefix) (length new-prefix)))
+                   (new-spacing (if (and (match-string 2)
+                                         (not (string-match "\t" old-spacing))
+                                         (< space-adjust 0)
+                                         (> space-adjust (- 1 (length (match-string 2)))))
+                                    (substring (match-string 2) 0 space-adjust)
+                                  (or old-spacing ". "))))
+              (insert (concat new-indent new-prefix new-spacing)))))
+         ;; Unordered list
+         ((string-match "[\\*\\+-]" marker)
+          (insert new-indent marker)))))))
+
+(defun markdown-move-list-item-up ()
+  "Move the current list item up in the list when possible."
+  (interactive)
+  (let (cur prev old)
+    (when (setq cur (markdown-cur-list-item-bounds))
+      (setq old (point))
+      (goto-char (nth 0 cur))
+      (if (markdown-prev-list-item (nth 3 cur))
+          (progn
+            (setq prev (markdown-cur-list-item-bounds))
+            (condition-case nil
+                (progn
+                  (transpose-regions (nth 0 prev) (nth 1 prev)
+                                     (nth 0 cur) (nth 1 cur) t)
+                  (goto-char (+ (nth 0 prev) (- old (nth 0 cur)))))
+              ;; Catch error in case regions overlap.
+              (error (goto-char old))))
+        (goto-char old)))))
+
+(defun markdown-move-list-item-down ()
+  "Move the current list item down in the list when possible."
+  (interactive)
+  (let (cur next old)
+    (when (setq cur (markdown-cur-list-item-bounds))
+      (setq old (point))
+      (if (markdown-next-list-item (nth 3 cur))
+          (progn
+            (setq next (markdown-cur-list-item-bounds))
+            (condition-case nil
+                (progn
+                  (transpose-regions (nth 0 cur) (nth 1 cur)
+                                     (nth 0 next) (nth 1 next) nil)
+                  (goto-char (+ old (- (nth 1 next) (nth 1 cur)))))
+              ;; Catch error in case regions overlap.
+              (error (goto-char old))))
+        (goto-char old)))))
+
+(defun markdown-demote-list-item (&optional bounds)
+  "Indent (or demote) the current list item.
+Optionally, BOUNDS of the current list item may be provided if available."
+  (interactive)
+  (when (or bounds (setq bounds (markdown-cur-list-item-bounds)))
+    (save-excursion
+      (save-match-data
+        (let ((end-marker (set-marker (make-marker) (nth 1 bounds))))
+          (goto-char (nth 0 bounds))
+          (while (< (point) end-marker)
+            (unless (markdown-cur-line-blank-p)
+              (insert (make-string markdown-list-indent-width ? )))
+            (forward-line)))))))
+
+(defun markdown-promote-list-item (&optional bounds)
+  "Unindent (or promote) the current list item.
+Optionally, BOUNDS of the current list item may be provided if available."
+  (interactive)
+  (when (or bounds (setq bounds (markdown-cur-list-item-bounds)))
+    (save-excursion
+      (save-match-data
+        (let ((end-marker (set-marker (make-marker) (nth 1 bounds)))
+              num regexp)
+          (goto-char (nth 0 bounds))
+          (when (looking-at (format "^[ ]\\{1,%d\\}"
+                                    markdown-list-indent-width))
+            (setq num (- (match-end 0) (match-beginning 0)))
+            (setq regexp (format "^[ ]\\{1,%d\\}" num))
+            (while (and (< (point) end-marker)
+                        (re-search-forward regexp end-marker t))
+              (replace-match "" nil nil)
+              (forward-line))))))))
+
+(defun markdown-cleanup-list-numbers-level (&optional pfx)
+  "Update the numbering for level PFX (as a string of spaces).
+
+Assume that the previously found match was for a numbered item in
+a list."
+  (let ((cpfx pfx)
+        (idx 0)
+        (continue t)
+        (step t)
+        (sep nil))
+    (while (and continue (not (eobp)))
+      (setq step t)
+      (cond
+       ((looking-at "^\\([\s-]*\\)[0-9]+\\. ")
+        (setq cpfx (match-string-no-properties 1))
+        (cond
+         ((string= cpfx pfx)
+          (replace-match
+           (concat pfx (number-to-string  (setq idx (1+ idx))) ". "))
+          (setq sep nil))
+         ;; indented a level
+         ((string< pfx cpfx)
+          (setq sep (markdown-cleanup-list-numbers-level cpfx))
+          (setq step nil))
+         ;; exit the loop
+         (t
+          (setq step nil)
+          (setq continue nil))))
+
+       ((looking-at "^\\([\s-]*\\)[^ \t\n\r].*$")
+        (setq cpfx (match-string-no-properties 1))
+        (cond
+         ;; reset if separated before
+         ((string= cpfx pfx) (when sep (setq idx 0)))
+         ((string< cpfx pfx)
+          (setq step nil)
+          (setq continue nil))))
+       (t (setq sep t)))
+
+      (when step
+        (beginning-of-line)
+        (setq continue (= (forward-line) 0))))
+    sep))
+
+(defun markdown-cleanup-list-numbers ()
+  "Update the numbering of ordered lists."
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+    (markdown-cleanup-list-numbers-level "")))
+
+
+;;; Movement ==================================================================
+
+(defun markdown-beginning-of-defun (&optional arg)
+  "`beginning-of-defun-function' for Markdown.
+Move backward to the beginning of the current or previous section.
+When ARG is non-nil, repeat that many times.  When ARG is negative,
+move forward to the ARG-th following section."
+  (interactive "P")
+  (or arg (setq arg 1))
+  (forward-char 1)
+  (or (re-search-backward markdown-regex-header nil t arg)
+      (goto-char (point-min))))
+
+(defun markdown-end-of-defun (&optional arg)
+  "`end-of-defun-function' for Markdown.
+Move forward to the end of the current or following section.
+When ARG is non-nil, repeat that many times.  When ARG is negative,
+move back to the ARG-th preceding section."
+  (interactive "P")
+  (or arg (setq arg 1))
+  (when (looking-at markdown-regex-header)
+    (goto-char (match-beginning 0))
+    (forward-char 1))
+  (if (re-search-forward markdown-regex-header nil t arg)
+      (goto-char (match-beginning 0))
+    (goto-char (point-max)))
+  (skip-syntax-backward "-"))
+
+(defun markdown-beginning-of-block ()
+  "Move the point to the start of the previous text block."
+  (interactive)
+  (if (re-search-backward markdown-regex-block-separator nil t)
+      (goto-char (or (match-end 2) (match-end 0)))
+    (goto-char (point-min))))
+
+(defun markdown-end-of-block ()
+  "Move the point to the start of the next text block."
+  (interactive)
+  (beginning-of-line)
+  (skip-syntax-forward "-")
+  (when (= (point) (point-min))
+    (forward-char))
+  (if (re-search-forward markdown-regex-block-separator nil t)
+      (goto-char (or (match-end 2) (match-end 0)))
+    (goto-char (point-max)))
+  (skip-syntax-backward "-")
+  (forward-line))
+
+(defun markdown-forward-paragraph (arg)
+  "Move forward one or more paragraphs or by one block.
+When ARG is nil or a numeric prefix, call `forward-paragraph'
+with ARG.  When called with \\[universal-argument], call
+`markdown-end-of-block' instead."
+  (interactive "P")
+  (or arg (setq arg 1))
+  (cond ((integerp arg)
+         (forward-paragraph arg))
+        ((equal arg '(4))
+         (markdown-end-of-block))))
+
+(defun markdown-backward-paragraph (arg)
+  "Move backward one or more paragraphs or by one block.
+When ARG is nil or a numeric prefix, call `backward-paragraph'
+with ARG.  When called with \\[universal-argument], call
+`markdown-beginning-of-block' instead."
+  (interactive "P")
+  (or arg (setq arg 1))
+  (cond ((integerp arg)
+         (backward-paragraph arg))
+        ((equal arg '(4))
+         (markdown-beginning-of-block))))
+
+(defun markdown-end-of-block-element ()
+  "Move the point to the start of the next block unit.
+Stops at blank lines, list items, headers, and horizontal rules."
+  (interactive)
+  (forward-line)
+  (while (and (or (not (markdown-prev-line-blank-p))
+                  (markdown-cur-line-blank-p))
+              (not (or (looking-at markdown-regex-list)
+                       (looking-at markdown-regex-header)
+                       (looking-at markdown-regex-hr)))
+              (not (eobp)))
+    (forward-line)))
+
+(defun markdown-next-link ()
+  "Jump to next inline, reference, or wiki link.
+If successful, return point.  Otherwise, return nil.
+See `markdown-wiki-link-p' and `markdown-previous-wiki-link'."
+  (interactive)
+  (let ((opoint (point)))
+    (when (or (markdown-link-p) (markdown-wiki-link-p))
+      ;; At a link already, move past it.
+      (goto-char (+ (match-end 0) 1)))
+    ;; Search for the next wiki link and move to the beginning.
+    (while (and (re-search-forward markdown-regex-link-generic nil t)
+                (markdown-code-block-at-point)
+                (< (point) (point-max))))
+    (if (and (not (eq (point) opoint))
+             (or (markdown-link-p) (markdown-wiki-link-p)))
+        ;; Group 1 will move past non-escape character in wiki link regexp.
+        ;; Go to beginning of group zero for all other link types.
+        (goto-char (or (match-beginning 1) (match-beginning 0)))
+      (goto-char opoint)
+      nil)))
+
+(defun markdown-previous-link ()
+  "Jump to previous wiki link.
+If successful, return point.  Otherwise, return nil.
+See `markdown-wiki-link-p' and `markdown-next-wiki-link'."
+  (interactive)
+  (let ((opoint (point)))
+    (while (and (re-search-backward markdown-regex-link-generic nil t)
+                (markdown-code-block-at-point)
+                (> (point) (point-min))))
+    (if (and (not (eq (point) opoint))
+             (or (markdown-link-p) (markdown-wiki-link-p)))
+        (goto-char (or (match-beginning 1) (match-beginning 0)))
+      (goto-char opoint)
+      nil)))
+
+(defun markdown-next-heading ()
+  "Move to the next heading line of any level.
+With argument, repeats or can move backward if negative."
+  (let ((pos (outline-next-heading)))
+    (while (markdown-code-block-at-point)
+      (setq pos (outline-next-heading)))
+    pos))
+
+(defun markdown-previous-heading ()
+  "Move to the previous heading line of any level.
+With argument, repeats or can move backward if negative."
+  (let ((pos (outline-previous-heading)))
+    (while (markdown-code-block-at-point)
+      (setq pos (outline-previous-heading)))
+    pos))
+
+
+;;; Outline ===================================================================
+
+(defun markdown-move-heading-common (move-fn &optional arg)
+  "Wrapper for `outline-mode' functions to skip false positives.
+For example, headings inside preformatted code blocks may match
+`outline-regexp' but should not be considered as headings."
+  (funcall move-fn arg)
+  (while (markdown-code-block-at-point)
+    (funcall move-fn arg)))
+
+(defun markdown-next-visible-heading (arg)
+  "Move to the next visible heading line of any level.
+With argument, repeats or can move backward if negative."
+  (interactive "p")
+  (markdown-move-heading-common 'outline-next-visible-heading arg))
+
+(defun markdown-previous-visible-heading (arg)
+  "Move to the previous visible heading line of any level.
+With argument, repeats or can move backward if negative."
+  (interactive "p")
+  (markdown-move-heading-common 'outline-previous-visible-heading arg))
+
+(defun markdown-forward-same-level (arg)
+  "Move forward to the ARG'th heading at same level as this one.
+Stop at the first and last headings of a superior heading."
+  (interactive "p")
+  (markdown-move-heading-common 'outline-forward-same-level arg))
+
+(defun markdown-backward-same-level (arg)
+  "Move backward to the ARG'th heading at same level as this one.
+Stop at the first and last headings of a superior heading."
+  (interactive "p")
+  (markdown-move-heading-common 'outline-backward-same-level arg))
+
+(defun markdown-up-heading (arg)
+  "Move to the visible heading line of which the present line is a subheading.
+With argument, move up ARG levels."
+  (interactive "p")
+  (markdown-move-heading-common 'outline-up-heading arg))
+
+(defun markdown-back-to-heading (&optional invisible-ok)
+  "Move to previous heading line, or beg of this line if it's a heading.
+Only visible heading lines are considered, unless INVISIBLE-OK is non-nil."
+  (markdown-move-heading-common 'outline-back-to-heading invisible-ok))
+
+(defalias 'markdown-end-of-heading 'outline-end-of-heading)
+
+(defun markdown-on-heading-p ()
+  "Return t if point is on a (visible) heading line."
+  (get-text-property (point) 'markdown-heading))
+
+(defun markdown-end-of-subtree (&optional invisible-OK)
+  "Move to the end of the current subtree.
+Only visible heading lines are considered, unless INVISIBLE-OK is
+non-nil.
+Derived from `org-end-of-subtree'."
+  (markdown-back-to-heading invisible-OK)
+  (let ((first t)
+        (level (funcall outline-level)))
+    (while (and (not (eobp))
+                (or first (> (funcall outline-level) level)))
+      (setq first nil)
+      (markdown-next-heading))
+    (if (memq (preceding-char) '(?\n ?\^M))
+        (progn
+          ;; Go to end of line before heading
+          (forward-char -1)
+          (if (memq (preceding-char) '(?\n ?\^M))
+              ;; leave blank line before heading
+              (forward-char -1)))))
+  (point))
+
+(defun markdown-outline-fix-visibility ()
+  "Hide any false positive headings that should not be shown.
+For example, headings inside preformatted code blocks may match
+`outline-regexp' but should not be shown as headings when cycling."
+  (save-excursion
+    (goto-char (point-min))
+    (unless (outline-on-heading-p)
+      (outline-next-visible-heading 1))
+    (while (< (point) (point-max))
+      (when (markdown-code-block-at-point)
+        (outline-flag-region (1- (point-at-bol)) (point-at-eol) t))
+      (outline-next-visible-heading 1))))
+
+(defvar markdown-cycle-global-status 1)
+(defvar markdown-cycle-subtree-status nil)
+
+(defun markdown-cycle (&optional arg)
+  "Visibility cycling for Markdown mode.
+If ARG is t, perform global visibility cycling.  If the point is
+at an atx-style header, cycle visibility of the corresponding
+subtree.  Otherwise, insert a tab using `indent-relative'.
+Derived from `org-cycle'."
+  (interactive "P")
+  (cond
+   ((eq arg t) ;; Global cycling
+    (cond
+     ((and (eq last-command this-command)
+           (eq markdown-cycle-global-status 2))
+      ;; Move from overview to contents
+      (markdown-hide-sublevels 1)
+      (message "CONTENTS")
+      (setq markdown-cycle-global-status 3)
+      (markdown-outline-fix-visibility))
+
+     ((and (eq last-command this-command)
+           (eq markdown-cycle-global-status 3))
+      ;; Move from contents to all
+      (markdown-show-all)
+      (message "SHOW ALL")
+      (setq markdown-cycle-global-status 1))
+
+     (t
+      ;; Defaults to overview
+      (markdown-hide-body)
+      (message "OVERVIEW")
+      (setq markdown-cycle-global-status 2)
+      (markdown-outline-fix-visibility))))
+
+   ((save-excursion (beginning-of-line 1) (markdown-on-heading-p))
+    ;; At a heading: rotate between three different views
+    (markdown-back-to-heading)
+    (let ((goal-column 0) eoh eol eos)
+      ;; Determine boundaries
+      (save-excursion
+        (markdown-back-to-heading)
+        (save-excursion
+          (beginning-of-line 2)
+          (while (and (not (eobp)) ;; this is like `next-line'
+                      (get-char-property (1- (point)) 'invisible))
+            (beginning-of-line 2)) (setq eol (point)))
+        (markdown-end-of-heading)   (setq eoh (point))
+        (markdown-end-of-subtree t)
+        (skip-chars-forward " \t\n")
+        (beginning-of-line 1) ; in case this is an item
+        (setq eos (1- (point))))
+      ;; Find out what to do next and set `this-command'
+      (cond
+       ((= eos eoh)
+        ;; Nothing is hidden behind this heading
+        (message "EMPTY ENTRY")
+        (setq markdown-cycle-subtree-status nil))
+       ((>= eol eos)
+        ;; Entire subtree is hidden in one line: open it
+        (markdown-show-entry)
+        (markdown-show-children)
+        (message "CHILDREN")
+        (setq markdown-cycle-subtree-status 'children))
+       ((and (eq last-command this-command)
+             (eq markdown-cycle-subtree-status 'children))
+        ;; We just showed the children, now show everything.
+        (markdown-show-subtree)
+        (message "SUBTREE")
+        (setq markdown-cycle-subtree-status 'subtree))
+       (t
+        ;; Default action: hide the subtree.
+        (markdown-hide-subtree)
+        (message "FOLDED")
+        (setq markdown-cycle-subtree-status 'folded)))))
+
+   (t
+    (indent-for-tab-command))))
+
+(defun markdown-shifttab ()
+  "Global visibility cycling.
+Calls `markdown-cycle' with argument t."
+  (interactive)
+  (markdown-cycle t))
+
+(defun markdown-outline-level ()
+  "Return the depth to which a statement is nested in the outline."
+  (cond
+   ((markdown-code-block-at-point) 7)
+   ((match-end 1) 1)
+   ((match-end 3) 2)
+   ((- (match-end 5) (match-beginning 5)))))
+
+(defun markdown-promote-subtree (&optional arg)
+  "Promote the current subtree of ATX headings.
+Note that Markdown does not support heading levels higher than six
+and therefore level-six headings will not be promoted further."
+  (interactive "*P")
+  (save-excursion
+    (when (and (or (thing-at-point-looking-at markdown-regex-header-atx)
+                   (re-search-backward markdown-regex-header-atx nil t))
+               (not (markdown-code-block-at-point)))
+      (let ((level (length (match-string 1)))
+            (promote-or-demote (if arg 1 -1))
+            (remove 't))
+        (markdown-cycle-atx promote-or-demote remove)
+        (catch 'end-of-subtree
+          (while (markdown-next-heading)
+            ;; Exit if this not a higher level heading; promote otherwise.
+            (if (and (looking-at markdown-regex-header-atx)
+                     (<= (length (match-string-no-properties 1)) level))
+                (throw 'end-of-subtree nil)
+              (markdown-cycle-atx promote-or-demote remove))))))))
+
+(defun markdown-demote-subtree ()
+  "Demote the current subtree of ATX headings."
+  (interactive)
+  (markdown-promote-subtree t))
+
+(defun markdown-move-subtree-up ()
+  "Move the current subtree of ATX headings up."
+  (interactive)
+  (outline-move-subtree-up 1))
+
+(defun markdown-move-subtree-down ()
+  "Move the current subtree of ATX headings down."
+  (interactive)
+  (outline-move-subtree-down 1))
+
+
+;;; Generic Structure Editing, Completion, and Cycling Commands ===============
+
+(defun markdown-move-up ()
+  "Move list item up.
+Calls `markdown-move-list-item-up'."
+  (interactive)
+  (markdown-move-list-item-up))
+
+(defun markdown-move-down ()
+  "Move list item down.
+Calls `markdown-move-list-item-down'."
+  (interactive)
+  (markdown-move-list-item-down))
+
+(defun markdown-promote ()
+  "Either promote header or list item at point or cycle markup.
+See `markdown-cycle-atx', `markdown-cycle-setext', and
+`markdown-promote-list-item'."
+  (interactive)
+  (let (bounds)
+    (cond
+     ;; Promote atx header
+     ((thing-at-point-looking-at markdown-regex-header-atx)
+      (markdown-cycle-atx -1))
+     ;; Promote setext header
+     ((thing-at-point-looking-at markdown-regex-header-setext)
+      (markdown-cycle-setext -1))
+     ;; Promote horizonal rule
+     ((thing-at-point-looking-at markdown-regex-hr)
+      (markdown-cycle-hr -1))
+     ;; Promote list item
+     ((setq bounds (markdown-cur-list-item-bounds))
+      (markdown-promote-list-item))
+     ;; Promote bold
+     ((thing-at-point-looking-at markdown-regex-bold)
+      (markdown-cycle-bold))
+     ;; Promote italic
+     ((thing-at-point-looking-at markdown-regex-italic)
+      (markdown-cycle-italic))
+     (t
+      (error "Nothing to promote at point")))))
+
+(defun markdown-demote ()
+  "Either demote header or list item at point or cycle or remove markup.
+See `markdown-cycle-atx', `markdown-cycle-setext', and
+`markdown-demote-list-item'."
+  (interactive)
+  (let (bounds)
+    (cond
+     ;; Demote atx header
+     ((thing-at-point-looking-at markdown-regex-header-atx)
+      (markdown-cycle-atx 1))
+     ;; Demote setext header
+     ((thing-at-point-looking-at markdown-regex-header-setext)
+      (markdown-cycle-setext 1))
+     ;; Demote horizonal rule
+     ((thing-at-point-looking-at markdown-regex-hr)
+      (markdown-cycle-hr 1))
+     ;; Demote list item
+     ((setq bounds (markdown-cur-list-item-bounds))
+      (markdown-demote-list-item))
+     ;; Demote bold
+     ((thing-at-point-looking-at markdown-regex-bold)
+      (markdown-cycle-bold))
+     ;; Demote italic
+     ((thing-at-point-looking-at markdown-regex-italic)
+      (markdown-cycle-italic))
+     (t
+      (error "Nothing to demote at point")))))
+
+
+;;; Commands ==================================================================
+
+(defun markdown (&optional output-buffer-name)
+  "Run `markdown-command' on buffer, sending output to OUTPUT-BUFFER-NAME.
+The output buffer name defaults to `markdown-output-buffer-name'.
+Return the name of the output buffer used."
+  (interactive)
+  (save-window-excursion
+    (let ((begin-region)
+          (end-region))
+      (if (markdown-use-region-p)
+          (setq begin-region (region-beginning)
+                end-region (region-end))
+        (setq begin-region (point-min)
+              end-region (point-max)))
+
+      (unless output-buffer-name
+        (setq output-buffer-name markdown-output-buffer-name))
+      (cond
+       ;; Handle case when `markdown-command' does not read from stdin
+       (markdown-command-needs-filename
+        (if (not buffer-file-name)
+            (error "Must be visiting a file")
+          (shell-command (concat markdown-command " "
+                                 (shell-quote-argument buffer-file-name))
+                         output-buffer-name)))
+       ;; Pass region to `markdown-command' via stdin
+       (t
+        (shell-command-on-region begin-region end-region markdown-command
+                                 output-buffer-name))))
+    output-buffer-name))
+
+(defun markdown-standalone (&optional output-buffer-name)
+  "Special function to provide standalone HTML output.
+Insert the output in the buffer named OUTPUT-BUFFER-NAME."
+  (interactive)
+  (setq output-buffer-name (markdown output-buffer-name))
+  (with-current-buffer output-buffer-name
+    (set-buffer output-buffer-name)
+    (unless (markdown-output-standalone-p)
+      (markdown-add-xhtml-header-and-footer output-buffer-name))
+    (goto-char (point-min))
+    (html-mode))
+  output-buffer-name)
+
+(defun markdown-other-window (&optional output-buffer-name)
+  "Run `markdown-command' on current buffer and display in other window.
+When OUTPUT-BUFFER-NAME is given, insert the output in the buffer with
+that name."
+  (interactive)
+  (markdown-display-buffer-other-window
+   (markdown-standalone output-buffer-name)))
+
+(defun markdown-output-standalone-p ()
+  "Determine whether `markdown-command' output is standalone XHTML.
+Standalone XHTML output is identified by an occurrence of
+`markdown-xhtml-standalone-regexp' in the first five lines of output."
+  (save-excursion
+    (goto-char (point-min))
+    (re-search-forward
+     markdown-xhtml-standalone-regexp
+     (save-excursion (goto-char (point-min)) (forward-line 4) (point))
+     t)))
+
+(defun markdown-stylesheet-link-string (stylesheet-path)
+  (concat "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\""
+          stylesheet-path
+          "\"  />"))
+
+(defun markdown-add-xhtml-header-and-footer (title)
+  "Wrap XHTML header and footer with given TITLE around current buffer."
+  (goto-char (point-min))
+  (insert "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+          "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
+          "\t\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n"
+          "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\n"
+          "<head>\n<title>")
+  (insert title)
+  (insert "</title>\n")
+  (when (> (length markdown-content-type) 0)
+    (insert
+     (format
+      "<meta http-equiv=\"Content-Type\" content=\"%s;charset=%s\"/>\n"
+      markdown-content-type
+      (or (and markdown-coding-system
+               (fboundp 'coding-system-get)
+               (coding-system-get markdown-coding-system
+                                  'mime-charset))
+          (and (fboundp 'coding-system-get)
+               (coding-system-get buffer-file-coding-system
+                                  'mime-charset))
+          "iso-8859-1"))))
+  (if (> (length markdown-css-paths) 0)
+      (insert (mapconcat 'markdown-stylesheet-link-string markdown-css-paths "\n")))
+  (when (> (length markdown-xhtml-header-content) 0)
+    (insert markdown-xhtml-header-content))
+  (insert "\n</head>\n\n"
+          "<body>\n\n")
+  (goto-char (point-max))
+  (insert "\n"
+          "</body>\n"
+          "</html>\n"))
+
+(defun markdown-preview (&optional output-buffer-name)
+  "Run `markdown-command' on the current buffer and view output in browser.
+When OUTPUT-BUFFER-NAME is given, insert the output in the buffer with
+that name."
+  (interactive)
+  (browse-url-of-buffer (markdown-standalone markdown-output-buffer-name)))
+
+(defun markdown-export-file-name (&optional extension)
+  "Attempt to generate a filename for Markdown output.
+The file extension will be EXTENSION if given, or .html by default.
+If the current buffer is visiting a file, we construct a new
+output filename based on that filename.  Otherwise, return nil."
+  (when (buffer-file-name)
+    (unless extension
+      (setq extension ".html"))
+    (let ((candidate
+           (concat
+            (cond
+             ((buffer-file-name)
+              (file-name-sans-extension (buffer-file-name)))
+             (t (buffer-name)))
+            extension)))
+      (cond
+       ((equal candidate (buffer-file-name))
+        (concat candidate extension))
+       (t
+        candidate)))))
+
+(defun markdown-export (&optional output-file)
+  "Run Markdown on the current buffer, save to file, and return the filename.
+If OUTPUT-FILE is given, use that as the filename.  Otherwise, use the filename
+generated by `markdown-export-file-name', which will be constructed using the
+current filename, but with the extension removed and replaced with .html."
+  (interactive)
+  (unless output-file
+    (setq output-file (markdown-export-file-name ".html")))
+  (when output-file
+    (let* ((init-buf (current-buffer))
+           (init-point (point))
+           (init-buf-string (buffer-string))
+           (output-buffer (find-file-noselect output-file))
+           (output-buffer-name (buffer-name output-buffer)))
+      (run-hooks 'markdown-before-export-hook)
+      (markdown-standalone output-buffer-name)
+      (with-current-buffer output-buffer
+        (run-hooks 'markdown-after-export-hook)
+        (save-buffer))
+      ;; if modified, restore initial buffer
+      (when (buffer-modified-p init-buf)
+        (erase-buffer)
+        (insert init-buf-string)
+        (save-buffer)
+        (goto-char init-point))
+      output-file)))
+
+(defun markdown-export-and-preview ()
+  "Export to XHTML using `markdown-export' and browse the resulting file."
+  (interactive)
+  (browse-url-of-file (markdown-export)))
+
+(defvar markdown-live-preview-buffer nil
+  "Buffer used to preview markdown output in `markdown-live-preview-export'.")
+(make-variable-buffer-local 'markdown-live-preview-buffer)
+
+(defvar markdown-live-preview-source-buffer nil
+  "Buffer with markdown source generating the source of the current
+buffer. Inverse of `markdown-live-preview-buffer'.")
+(make-variable-buffer-local 'markdown-live-preview-source-buffer)
+
+(defvar markdown-live-preview-currently-exporting nil)
+
+(defun markdown-live-preview-get-filename ()
+  "Standardize the filename exported by `markdown-live-preview-export'."
+  (markdown-export-file-name ".html"))
+
+(defun markdown-live-preview-window-eww (file)
+  "A `markdown-live-preview-window-function' for previewing with eww."
+  (if (require 'eww nil t)
+      (progn
+        (eww-open-file file)
+        (get-buffer "*eww*"))
+    (error "eww is not present or not loaded on this version of emacs")))
+
+(defun markdown-live-preview-window-serialize (buf)
+  "Get window point and scroll data for all windows displaying BUF if BUF is
+non-nil."
+  (when buf
+    (mapcar (lambda (win) (list win (window-point win) (window-start win)))
+            (get-buffer-window-list buf))))
+
+(defun markdown-live-preview-window-deserialize (window-posns)
+  "Apply window point and scroll data from WINDOW-POSNS, given by
+`markdown-live-preview-window-serialize'."
+  (cl-destructuring-bind (win pt start) window-posns
+    (when (window-live-p win)
+      (set-window-buffer win markdown-live-preview-buffer)
+      (set-window-point win pt)
+      (set-window-start win start))))
+
+(defun markdown-live-preview-export ()
+  "Export to XHTML using `markdown-export' and browse the resulting file within
+Emacs using `markdown-live-preview-window-function' Return the buffer displaying
+the rendered output."
+  (interactive)
+  (let* ((markdown-live-preview-currently-exporting t)
+         (cur-buf (current-buffer))
+         (export-file (markdown-export (markdown-live-preview-get-filename)))
+         ;; get positions in all windows currently displaying output buffer
+         (window-data
+          (markdown-live-preview-window-serialize
+           markdown-live-preview-buffer)))
+    (save-window-excursion
+      (let ((output-buffer
+             (funcall markdown-live-preview-window-function export-file)))
+        (with-current-buffer output-buffer
+          (setq markdown-live-preview-source-buffer cur-buf)
+          (add-hook 'kill-buffer-hook
+                    #'markdown-live-preview-remove-on-kill t t))
+        (with-current-buffer cur-buf
+          (setq markdown-live-preview-buffer output-buffer))))
+    (with-current-buffer cur-buf
+      ;; reset all windows displaying output buffer to where they were,
+      ;; now with the new output
+      (mapc #'markdown-live-preview-window-deserialize window-data)
+      ;; delete html editing buffer
+      (let ((buf (get-file-buffer export-file))) (when buf (kill-buffer buf)))
+      (when (and export-file (file-exists-p export-file)
+                 (eq markdown-live-preview-delete-export
+                     'delete-on-export))
+        (delete-file export-file))
+      markdown-live-preview-buffer)))
+
+(defun markdown-live-preview-remove ()
+  (when (buffer-live-p markdown-live-preview-buffer)
+    (kill-buffer markdown-live-preview-buffer))
+  (setq markdown-live-preview-buffer nil)
+  ;; if set to 'delete-on-export, the output has already been deleted
+  (when (eq markdown-live-preview-delete-export 'delete-on-destroy)
+    (let ((outfile-name (markdown-live-preview-get-filename)))
+      (when (file-exists-p outfile-name)
+        (delete-file outfile-name)))))
+
+(defun markdown-display-buffer-other-window (buf)
+  (let ((cur-buf (current-buffer)))
+    (switch-to-buffer-other-window buf)
+    (set-buffer cur-buf)))
+
+(defun markdown-live-preview-if-markdown ()
+  (when (and (derived-mode-p 'markdown-mode)
+             markdown-live-preview-mode)
+    (unless markdown-live-preview-currently-exporting
+      (if (buffer-live-p markdown-live-preview-buffer)
+          (markdown-live-preview-export)
+        (markdown-display-buffer-other-window
+         (markdown-live-preview-export))))))
+
+(defun markdown-live-preview-remove-on-kill ()
+  (cond ((and (derived-mode-p 'markdown-mode)
+              markdown-live-preview-mode)
+         (markdown-live-preview-remove))
+        (markdown-live-preview-source-buffer
+         (with-current-buffer markdown-live-preview-source-buffer
+           (setq markdown-live-preview-buffer nil))
+         (setq markdown-live-preview-source-buffer nil))))
+
+(defun markdown-live-preview-switch-to-output ()
+  (interactive)
+  "Turn on `markdown-live-preview-mode' if not already on, and switch to its
+output buffer in another window."
+  (if markdown-live-preview-mode
+      (markdown-display-buffer-other-window (markdown-live-preview-export)))
+    (markdown-live-preview-mode))
+
+(defun markdown-live-preview-re-export ()
+  (interactive)
+  "If the current buffer is a buffer displaying the exported version of a
+`markdown-live-preview-mode' buffer, call `markdown-live-preview-export' and
+update this buffer's contents."
+  (when markdown-live-preview-source-buffer
+    (with-current-buffer markdown-live-preview-source-buffer
+      (markdown-live-preview-export))))
+
+(defun markdown-open ()
+  "Open file for the current buffer with `markdown-open-command'."
+  (interactive)
+  (if (not markdown-open-command)
+      (error "Variable `markdown-open-command' must be set")
+    (if (not buffer-file-name)
+        (error "Must be visiting a file")
+      (call-process markdown-open-command
+                    nil nil nil buffer-file-name))))
+
+(defun markdown-kill-ring-save ()
+  "Run Markdown on file and store output in the kill ring."
+  (interactive)
+  (save-window-excursion
+    (markdown)
+    (with-current-buffer markdown-output-buffer-name
+      (kill-ring-save (point-min) (point-max)))))
+
+
+;;; Links =====================================================================
+
+(defun markdown-link-p ()
+  "Return non-nil when `point' is at a non-wiki link.
+See `markdown-wiki-link-p' for more information."
+  (let ((case-fold-search nil))
+    (and (not (markdown-wiki-link-p))
+         (not (markdown-code-block-at-point))
+         (or (thing-at-point-looking-at markdown-regex-link-inline)
+             (thing-at-point-looking-at markdown-regex-link-reference)
+             (thing-at-point-looking-at markdown-regex-uri)
+             (thing-at-point-looking-at markdown-regex-angle-uri)))))
+
+(defun markdown-link-link ()
+  "Return the link part of the regular (non-wiki) link at point.
+Works with both inline and reference style links.  If point is
+not at a link or the link reference is not defined returns nil."
+  (cond
+   ((thing-at-point-looking-at markdown-regex-link-inline)
+    (match-string-no-properties 6))
+   ((thing-at-point-looking-at markdown-regex-link-reference)
+    (let* ((text (match-string-no-properties 3))
+           (reference (match-string-no-properties 6))
+           (target (downcase (if (string= reference "") text reference))))
+      (car (markdown-reference-definition target))))
+   ((thing-at-point-looking-at markdown-regex-uri)
+    (match-string-no-properties 0))
+   ((thing-at-point-looking-at markdown-regex-angle-uri)
+    (match-string-no-properties 2))
+   (t nil)))
+
+(defun markdown-follow-link-at-point ()
+  "Open the current non-wiki link in a browser."
+  (interactive)
+  (if (markdown-link-p) (browse-url (markdown-link-link))
+    (error "Point is not at a Markdown link or URI")))
+
+
+;;; WikiLink Following/Markup =================================================
+
+(defun markdown-wiki-link-p ()
+  "Return non-nil when `point' is at a true wiki link.
+A true wiki link name matches `markdown-regex-wiki-link' but does not
+match the current file name after conversion.  This modifies the data
+returned by `match-data'.  Note that the potential wiki link name must
+be available via `match-string'."
+  (let ((case-fold-search nil))
+    (and (thing-at-point-looking-at markdown-regex-wiki-link)
+         (not (markdown-code-block-at-point))
+         (or (not buffer-file-name)
+             (not (string-equal (buffer-file-name)
+                                (markdown-convert-wiki-link-to-filename
+                                 (markdown-wiki-link-link))))))))
+
+(defun markdown-wiki-link-link ()
+  "Return the link part of the wiki link using current match data.
+The location of the link component depends on the value of
+`markdown-wiki-link-alias-first'."
+  (if markdown-wiki-link-alias-first
+      (or (match-string-no-properties 5) (match-string-no-properties 3))
+    (match-string-no-properties 3)))
+
+(defun markdown-wiki-link-alias ()
+  "Return the alias or text part of the wiki link using current match data.
+The location of the alias component depends on the value of
+`markdown-wiki-link-alias-first'."
+  (if markdown-wiki-link-alias-first
+      (match-string-no-properties 3)
+    (or (match-string-no-properties 5) (match-string-no-properties 3))))
+
+(defun markdown-convert-wiki-link-to-filename (name)
+  "Generate a filename from the wiki link NAME.
+Spaces in NAME are replaced with `markdown-link-space-sub-char'.
+When in `gfm-mode', follow GitHub's conventions where [[Test Test]]
+and [[test test]] both map to Test-test.ext."
+  (let ((basename (markdown-replace-regexp-in-string
+                   "[[:space:]\n]" markdown-link-space-sub-char name)))
+    (when (eq major-mode 'gfm-mode)
+      (setq basename (concat (upcase (substring basename 0 1))
+                             (downcase (substring basename 1 nil)))))
+    (let* ((default
+            (concat basename
+                    (if (and (buffer-file-name)
+                             (file-name-extension (buffer-file-name)))
+                        (concat "."
+                                (file-name-extension (buffer-file-name))))))
+           (current default))
+      (catch 'done
+        (condition-case nil
+            (cl-loop
+             (if (or (not markdown-wiki-link-search-parent-directories)
+                     (file-exists-p current))
+                 (throw 'done current))
+             (if (string-equal (expand-file-name current)
+                               (concat "/" default))
+                 (throw 'done default))
+             (setq current (concat "../" current)))
+          (error default))))))
+
+(defun markdown-follow-wiki-link (name &optional other)
+  "Follow the wiki link NAME.
+Convert the name to a file name and call `find-file'.  Ensure that
+the new buffer remains in `markdown-mode'.  Open the link in another
+window when OTHER is non-nil."
+  (let ((filename (markdown-convert-wiki-link-to-filename name))
+        (wp (file-name-directory buffer-file-name)))
+    (when other (other-window 1))
+    (let ((default-directory wp))
+      (find-file filename)))
+  (when (not (eq major-mode 'markdown-mode))
+    (markdown-mode)))
+
+(defun markdown-follow-wiki-link-at-point (&optional arg)
+  "Find Wiki Link at point.
+With prefix argument ARG, open the file in other window.
+See `markdown-wiki-link-p' and `markdown-follow-wiki-link'."
+  (interactive "P")
+  (if (markdown-wiki-link-p)
+      (markdown-follow-wiki-link (markdown-wiki-link-link) arg)
+    (error "Point is not at a Wiki Link")))
+
+(defun markdown-highlight-wiki-link (from to face)
+  "Highlight the wiki link in the region between FROM and TO using FACE."
+  (put-text-property from to 'font-lock-face face))
+
+(defun markdown-unfontify-region-wiki-links (from to)
+  "Remove wiki link faces from the region specified by FROM and TO."
+  (interactive "*r")
+  (remove-text-properties from to '(font-lock-face markdown-link-face))
+  (remove-text-properties from to '(font-lock-face markdown-missing-link-face)))
+
+(defun markdown-fontify-region-wiki-links (from to)
+  "Search region given by FROM and TO for wiki links and fontify them.
+If a wiki link is found check to see if the backing file exists
+and highlight accordingly."
+  (goto-char from)
+  (save-match-data
+    (while (re-search-forward markdown-regex-wiki-link to t)
+      (when (not (markdown-code-block-at-point))
+        (let ((highlight-beginning (match-beginning 1))
+              (highlight-end (match-end 1))
+              (file-name
+               (markdown-convert-wiki-link-to-filename
+                (markdown-wiki-link-link))))
+          (if (condition-case nil (file-exists-p file-name) (error nil))
+              (markdown-highlight-wiki-link
+               highlight-beginning highlight-end markdown-link-face)
+            (markdown-highlight-wiki-link
+             highlight-beginning highlight-end markdown-missing-link-face)))))))
+
+(defun markdown-extend-changed-region (from to)
+  "Extend region given by FROM and TO so that we can fontify all links.
+The region is extended to the first newline before and the first
+newline after."
+  ;; start looking for the first new line before 'from
+  (goto-char from)
+  (re-search-backward "\n" nil t)
+  (let ((new-from (point-min))
+        (new-to (point-max)))
+    (if (not (= (point) from))
+        (setq new-from (point)))
+    ;; do the same thing for the first new line after 'to
+    (goto-char to)
+    (re-search-forward "\n" nil t)
+    (if (not (= (point) to))
+        (setq new-to (point)))
+    (cl-values new-from new-to)))
+
+(defun markdown-check-change-for-wiki-link (from to)
+  "Check region between FROM and TO for wiki links and re-fontify as needed."
+  (interactive "*r")
+  (let* ((modified (buffer-modified-p))
+         (buffer-undo-list t)
+         (inhibit-read-only t)
+         (inhibit-point-motion-hooks t)
+         deactivate-mark
+         buffer-file-truename)
+    (unwind-protect
+        (save-excursion
+          (save-match-data
+            (save-restriction
+              ;; Extend the region to fontify so that it starts
+              ;; and ends at safe places.
+              (cl-multiple-value-bind (new-from new-to)
+                  (markdown-extend-changed-region from to)
+                (goto-char new-from)
+                ;; Only refontify when the range contains text with a
+                ;; wiki link face or if the wiki link regexp matches.
+                (when (or (markdown-range-property-any
+                           new-from new-to 'font-lock-face
+                           (list markdown-link-face
+                                 markdown-missing-link-face))
+                          (re-search-forward
+                           markdown-regex-wiki-link new-to t))
+                  ;; Unfontify existing fontification (start from scratch)
+                  (markdown-unfontify-region-wiki-links new-from new-to)
+                  ;; Now do the fontification.
+                  (markdown-fontify-region-wiki-links new-from new-to))))))
+      (and (not modified)
+           (buffer-modified-p)
+           (set-buffer-modified-p nil)))))
+
+(defun markdown-check-change-for-wiki-link-after-change (from to _)
+    "Check region between FROM and TO for wiki links and re-fontify as needed.
+Designed to be used with the `after-change-functions' hook."
+  (markdown-check-change-for-wiki-link from to))
+
+(defun markdown-fontify-buffer-wiki-links ()
+  "Refontify all wiki links in the buffer."
+  (interactive)
+  (markdown-check-change-for-wiki-link (point-min) (point-max)))
+
+
+;;; Following and Jumping =====================================================
+
+(defun markdown-follow-thing-at-point (arg)
+  "Follow thing at point if possible, such as a reference link or wiki link.
+Opens inline and reference links in a browser.  Opens wiki links
+to other files in the current window, or the another window if
+ARG is non-nil.
+See `markdown-follow-link-at-point' and
+`markdown-follow-wiki-link-at-point'."
+  (interactive "P")
+  (cond ((markdown-link-p)
+         (markdown-follow-link-at-point))
+        ((markdown-wiki-link-p)
+         (markdown-follow-wiki-link-at-point arg))
+        (t
+         (error "Nothing to follow at point"))))
+
+(defun markdown-jump ()
+  "Jump to another location based on context at point.
+Jumps between reference links and definitions; between footnote
+markers and footnote text."
+  (interactive)
+  (cond ((markdown-footnote-text-positions)
+         (markdown-footnote-return))
+        ((markdown-footnote-marker-positions)
+         (markdown-footnote-goto-text))
+        ((thing-at-point-looking-at markdown-regex-link-reference)
+         (markdown-reference-goto-definition))
+        ((thing-at-point-looking-at markdown-regex-reference-definition)
+         (markdown-reference-goto-link (match-string-no-properties 2)))
+        (t
+         (error "Nothing to jump to from context at point"))))
+
+
+;;; Miscellaneous =============================================================
+
+(defun markdown-compress-whitespace-string (str)
+  "Compress whitespace in STR and return result.
+Leading and trailing whitespace is removed.  Sequences of multiple
+spaces, tabs, and newlines are replaced with single spaces."
+  (markdown-replace-regexp-in-string "\\(^[ \t\n]+\\|[ \t\n]+$\\)" ""
+                            (markdown-replace-regexp-in-string "[ \t\n]+" " " str)))
+
+(defun markdown-line-number-at-pos (&optional pos)
+  "Return (narrowed) buffer line number at position POS.
+If POS is nil, use current buffer location.
+This is an exact copy of `line-number-at-pos' for use in emacs21."
+  (let ((opoint (or pos (point))) start)
+    (save-excursion
+      (goto-char (point-min))
+      (setq start (point))
+      (goto-char opoint)
+      (forward-line 0)
+      (1+ (count-lines start (point))))))
+
+(defun markdown-inside-link-text-p ()
+  "Return nil if not currently within link anchor text."
+  (looking-back "\\[[^]]*" nil))
+
+(defun markdown-line-is-reference-definition-p ()
+  "Return whether the current line is a (non-footnote) reference defition."
+  (save-excursion
+    (move-beginning-of-line 1)
+    (and (looking-at-p markdown-regex-reference-definition)
+         (not (looking-at-p "[ \t]*\\[^")))))
+
+(defun markdown-adaptive-fill-function ()
+  "Return prefix for filling paragraph or nil if not determined."
+  (cond
+   ;; List item inside blockquote
+   ((looking-at "^[ \t]*>[ \t]*\\(\\(?:[0-9]+\\|#\\)\\.\\|[*+-]\\)[ \t]+")
+    (markdown-replace-regexp-in-string
+     "[0-9\\.*+-]" " " (match-string-no-properties 0)))
+   ;; Blockquote
+   ((looking-at "^[ \t]*>[ \t]*")
+    (match-string-no-properties 0))
+   ;; List items
+   ((looking-at markdown-regex-list)
+    (match-string-no-properties 0))
+   ((looking-at markdown-regex-footnote-definition)
+    "    ") ; four spaces
+   ;; No match
+   (t nil)))
+
+(defun markdown-fill-forward-paragraph-function (&optional arg)
+  (let* ((arg (or arg 1))
+         (paragraphs-remaining (forward-paragraph arg))
+         (start (point)))
+    (when (< arg 0)
+      (while (and (not (eobp))
+                  (progn (move-to-left-margin) (not (eobp)))
+                  (looking-at paragraph-separate))
+        (forward-line 1))
+      (if (looking-at markdown-regex-list)
+          (forward-char (length (match-string 0)))
+        (goto-char start)))
+    paragraphs-remaining))
+
+
+;;; Extensions ================================================================
+
+(defun markdown-reload-extensions ()
+  "Check settings, update font-lock keywords, and re-fontify buffer."
+  (interactive)
+  (when (eq major-mode 'markdown-mode)
+    (setq markdown-mode-font-lock-keywords
+          (append
+           markdown-mode-font-lock-keywords-basic
+           (when markdown-enable-math
+             markdown-mode-font-lock-keywords-math)))
+    (setq font-lock-defaults
+          '(markdown-mode-font-lock-keywords
+            nil nil nil nil
+            (font-lock-syntactic-face-function . markdown-syntactic-face)))
+    (when (fboundp 'font-lock-refresh-defaults) (font-lock-refresh-defaults))))
+
+(defun markdown-enable-math (&optional arg)
+  "Toggle support for inline and display LaTeX math expressions.
+With a prefix argument ARG, enable math mode if ARG is positive,
+and disable it otherwise.  If called from Lisp, enable the mode
+if ARG is omitted or nil."
+  (interactive (list (or current-prefix-arg 'toggle)))
+  (setq markdown-enable-math
+        (if (eq arg 'toggle)
+            (not markdown-enable-math)
+          (> (prefix-numeric-value arg) 0)))
+  (if markdown-enable-math
+      (message "markdown-mode math support enabled")
+    (message "markdown-mode math support disabled"))
+  (markdown-reload-extensions))
+
+(defun markdown-handle-local-variables ()
+  "Runs as a `hack-local-variables-hook' to update font lock rules.
+Checks to see if there is actually a markdown-mode file local variable
+before regenerating font-lock rules for extensions."
+  (when (and (boundp 'file-local-variables-alist)
+             (assoc 'markdown-enable-math file-local-variables-alist))
+    (markdown-reload-extensions)))
+
+
+;;; GFM Checkboxes as Buttons =================================================
+
+(require 'button)
+
+(define-button-type 'markdown-gfm-checkbox-button
+  'follow-link t
+  'face 'markdown-gfm-checkbox-face
+  'mouse-face 'markdown-highlight-face
+  'action #'markdown-toggle-gfm-checkbox)
+
+(defun markdown-toggle-gfm-checkbox (button)
+  "Toggle a GFM checkbox clicked on."
+  (save-match-data
+    (save-excursion
+      (goto-char (button-start button))
+      (cond ((looking-at "\\[ \\]")
+             (replace-match "[x]" nil t))
+            ((looking-at "\\[[xX]\\]")
+             (replace-match "[ ]" nil t))))))
+
+(defun markdown-make-gfm-checkboxes-buttons (start end)
+  "Make GFM checkboxes buttons in region between START and END."
+  (save-excursion
+    (goto-char start)
+    (let ((case-fold-search t))
+      (save-excursion
+	(while (re-search-forward markdown-regex-gfm-checkbox end t)
+	  (make-button (match-beginning 1) (match-end 1)
+                       :type 'markdown-gfm-checkbox-button))))))
+
+;; Called when any modification is made to buffer text.
+(defun markdown-gfm-checkbox-after-change-function (beg end old-len)
+  "Add to `after-change-functions' to setup GFM checkboxes as buttons."
+  (save-excursion
+    (save-match-data
+      ;; Rescan between start of line from `beg' and start of line after `end'.
+      (markdown-make-gfm-checkboxes-buttons
+       (progn (goto-char beg) (beginning-of-line) (point))
+       (progn (goto-char end) (forward-line 1) (point))))))
+
+
+;;; Mode Definition  ==========================================================
+
+(defun markdown-show-version ()
+  "Show the version number in the minibuffer."
+  (interactive)
+  (message "markdown-mode, version %s" markdown-mode-version))
+
+;;;###autoload
+(define-derived-mode markdown-mode text-mode "Markdown"
+  "Major mode for editing Markdown files."
+  ;; Natural Markdown tab width
+  (setq tab-width 4)
+  ;; Comments
+  (make-local-variable 'comment-start)
+  (setq comment-start "<!-- ")
+  (make-local-variable 'comment-end)
+  (setq comment-end " -->")
+  (make-local-variable 'comment-start-skip)
+  (setq comment-start-skip "<!--[ \t]*")
+  (make-local-variable 'comment-column)
+  (setq comment-column 0)
+  (set (make-local-variable 'comment-auto-fill-only-comments) nil)
+  ;; Syntax
+  (add-hook 'syntax-propertize-extend-region-functions
+            'markdown-syntax-propertize-extend-region)
+  (set (make-local-variable 'syntax-propertize-function)
+       'markdown-syntax-propertize)
+  ;; Font lock.
+  (set (make-local-variable 'markdown-mode-font-lock-keywords) nil)
+  (set (make-local-variable 'font-lock-defaults) nil)
+  (set (make-local-variable 'font-lock-multiline) t)
+  ;; Extensions
+  (make-local-variable 'markdown-enable-math)
+  ;; Reload extensions
+  (markdown-reload-extensions)
+  ;; Add a buffer-local hook to reload after file-local variables are read
+  (add-hook 'hack-local-variables-hook 'markdown-handle-local-variables nil t)
+  ;; For imenu support
+  (setq imenu-create-index-function 'markdown-imenu-create-index)
+  ;; For menu support in XEmacs
+  (easy-menu-add markdown-mode-menu markdown-mode-map)
+  ;; Defun movement
+  (set (make-local-variable 'beginning-of-defun-function)
+       'markdown-beginning-of-defun)
+  (set (make-local-variable 'end-of-defun-function)
+       'markdown-end-of-defun)
+  ;; Paragraph filling
+  (set
+   ; Should match start of lines that start or separate paragraphs
+   (make-local-variable 'paragraph-start)
+       (mapconcat 'identity
+                  '(
+                    "\f" ; starts with a literal line-feed
+                    "[ \t\f]*$" ; space-only line
+                    "[ \t]*[*+-][ \t]+" ; unordered list item
+                    "[ \t]*\\(?:[0-9]+\\|#\\)\\.[ \t]+" ; ordered list item
+                    "[ \t]*\\[\\S-*\\]:[ \t]+" ; link ref def
+                    "[ \t]*:[ \t]+" ; definition
+                    )
+                  "\\|"))
+  (set
+   ; Should match lines that separate paragraphs without being
+   ; part of any paragraph:
+   (make-local-variable 'paragraph-separate)
+   (mapconcat 'identity
+              '("[ \t\f]*$" ; space-only line
+                ; The following is not ideal, but the Fill customization
+                ; options really only handle paragraph-starting prefixes,
+                ; not paragraph-ending suffixes:
+                ".*  $" ; line ending in two spaces
+                "[ \t]*\\[\\^\\S-*\\]:[ \t]*$") ; just the start of a footnote def
+              "\\|"))
+  (set (make-local-variable 'adaptive-fill-first-line-regexp)
+       "\\`[ \t]*>[ \t]*?\\'")
+  (set (make-local-variable 'adaptive-fill-function)
+       'markdown-adaptive-fill-function)
+  (set (make-local-variable 'fill-forward-paragraph-function)
+       'markdown-fill-forward-paragraph-function)
+  ;; Outline mode
+  (make-local-variable 'outline-regexp)
+  (setq outline-regexp markdown-regex-header)
+  (make-local-variable 'outline-level)
+  (setq outline-level 'markdown-outline-level)
+  ;; Cause use of ellipses for invisible text.
+  (add-to-invisibility-spec '(outline . t))
+
+  ;; Inhibiting line-breaking:
+  ;; Separating out each condition into a separate function so that users can
+  ;; override if desired (with remove-hook)
+  (add-hook 'fill-nobreak-predicate
+            'markdown-inside-link-text-p nil t)
+  (add-hook 'fill-nobreak-predicate
+            'markdown-line-is-reference-definition-p nil t)
+
+  ;; Indentation
+  (setq indent-line-function markdown-indent-function)
+
+  ;; Backwards compatibility with markdown-css-path
+  (when (boundp 'markdown-css-path)
+    (warn "markdown-css-path is deprecated, see markdown-css-paths.")
+    (add-to-list 'markdown-css-paths markdown-css-path))
+
+  ;; Prepare hooks for XEmacs compatibility
+  (when (featurep 'xemacs)
+    (make-local-hook 'after-change-functions)
+    (make-local-hook 'font-lock-extend-region-functions)
+    (make-local-hook 'window-configuration-change-hook))
+
+  ;; Anytime text changes make sure it gets fontified correctly
+  (add-hook 'after-change-functions
+            'markdown-check-change-for-wiki-link-after-change t t)
+
+  ;; Make checkboxes buttons
+  (when markdown-make-gfm-checkboxes-buttons
+    (markdown-make-gfm-checkboxes-buttons (point-min) (point-max))
+    (add-hook 'after-change-functions 'markdown-gfm-checkbox-after-change-function t t))
+
+  ;; If we left the buffer there is a really good chance we were
+  ;; creating one of the wiki link documents. Make sure we get
+  ;; refontified when we come back.
+  (add-hook 'window-configuration-change-hook
+            'markdown-fontify-buffer-wiki-links t t)
+
+  ;; add live preview export hook
+  (add-hook 'after-save-hook #'markdown-live-preview-if-markdown t t)
+  (add-hook 'kill-buffer-hook #'markdown-live-preview-remove-on-kill t t)
+
+  ;; do the initial link fontification
+  (markdown-fontify-buffer-wiki-links))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.text\\'" . markdown-mode))
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
+
+
+;;; GitHub Flavored Markdown Mode  ============================================
+
+(defvar gfm-mode-hook nil
+  "Hook run when entering GFM mode.")
+
+(defvar gfm-font-lock-keywords
+  (append
+   ;; GFM features to match first
+   (list
+    (cons markdown-regex-strike-through '((3 markdown-markup-face)
+                                          (4 markdown-strike-through-face)
+                                          (5 markdown-markup-face))))
+   ;; Basic Markdown features (excluding possibly overridden ones)
+   markdown-mode-font-lock-keywords-basic)
+  "Default highlighting expressions for GitHub Flavored Markdown mode.")
+
+;;;###autoload
+(define-derived-mode gfm-mode markdown-mode "GFM"
+  "Major mode for editing GitHub Flavored Markdown files."
+  (setq markdown-link-space-sub-char "-")
+  (set (make-local-variable 'font-lock-defaults)
+       '(gfm-font-lock-keywords))
+  ;; do the initial link fontification
+  (markdown-fontify-buffer-wiki-links)
+  (markdown-gfm-parse-buffer-for-languages))
+
+
+;;; Live Preview Mode  ============================================
+(define-minor-mode markdown-live-preview-mode
+  "Toggle native previewing on save for a specific markdown file."
+  :lighter " MD-Preview"
+  (if markdown-live-preview-mode
+      (markdown-display-buffer-other-window (markdown-live-preview-export))
+    (markdown-live-preview-remove)))
+
+
+(provide 'markdown-mode)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; markdown-mode.el ends here
diff --git a/emacs.d/lisp/yaml-mode.el b/emacs.d/lisp/yaml-mode.el
new file mode 100644
index 0000000..615de6f
--- /dev/null
+++ b/emacs.d/lisp/yaml-mode.el
@@ -0,0 +1,439 @@
+;;; yaml-mode.el --- Major mode for editing YAML files
+
+;; Copyright (C) 2010-2014 Yoshiki Kurihara
+
+;; Author: Yoshiki Kurihara <clouder@gmail.com>
+;;         Marshall T. Vandegrift <llasram@gmail.com>
+;; Maintainer: Vasilij Schneidermann <v.schneidermann@gmail.com>
+;; Package-Requires: ((emacs "24.1"))
+;; Keywords: data yaml
+;; Version: 0.0.13
+
+;; This file is not part of Emacs
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License along
+;; with this program; if not, write to the Free Software Foundation, Inc.,
+;; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+;;; Commentary:
+
+;; This is a major mode for editing files in the YAML data
+;; serialization format.  It was initially developed by Yoshiki
+;; Kurihara and many features were added by Marshall Vandegrift.  As
+;; YAML and Python share the fact that indentation determines
+;; structure, this mode provides indentation and indentation command
+;; behavior very similar to that of python-mode.
+
+;;; Installation:
+
+;; To install, just drop this file into a directory in your
+;; `load-path' and (optionally) byte-compile it.  To automatically
+;; handle files ending in '.yml', add something like:
+;;
+;;    (require 'yaml-mode)
+;;    (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
+;;
+;; to your .emacs file.
+;;
+;; Unlike python-mode, this mode follows the Emacs convention of not
+;; binding the ENTER key to `newline-and-indent'.  To get this
+;; behavior, add the key definition to `yaml-mode-hook':
+;;
+;;    (add-hook 'yaml-mode-hook
+;;     '(lambda ()
+;;        (define-key yaml-mode-map "\C-m" 'newline-and-indent)))
+
+;;; Known Bugs:
+
+;; YAML is easy to write but complex to parse, and this mode doesn't
+;; even really try.  Indentation and highlighting will break on
+;; abnormally complicated structures.
+
+;;; Code:
+
+
+;; User definable variables
+
+;;;###autoload
+(defgroup yaml nil
+  "Support for the YAML serialization format"
+  :group 'languages
+  :prefix "yaml-")
+
+(defcustom yaml-mode-hook nil
+  "*Hook run by `yaml-mode'."
+  :type 'hook
+  :group 'yaml)
+
+(defcustom yaml-indent-offset 2
+  "*Amount of offset per level of indentation."
+  :type 'integer
+  :safe 'natnump
+  :group 'yaml)
+
+(defcustom yaml-backspace-function 'backward-delete-char-untabify
+  "*Function called by `yaml-electric-backspace' when deleting backwards.
+It will receive one argument, the numeric prefix value."
+  :type 'function
+  :group 'yaml)
+
+(defcustom yaml-block-literal-search-lines 100
+  "*Maximum number of lines to search for start of block literals."
+  :type 'integer
+  :group 'yaml)
+
+(defcustom yaml-block-literal-electric-alist
+  '((?| . "") (?> . "-"))
+  "*Characters for which to provide electric behavior.
+The association list key should be a key code and the associated value
+should be a string containing additional characters to insert when
+that key is pressed to begin a block literal."
+  :type 'alist
+  :group 'yaml)
+
+(defface yaml-tab-face
+   '((((class color)) (:background "red" :foreground "red" :bold t))
+     (t (:reverse-video t)))
+  "Face to use for highlighting tabs in YAML files."
+  :group 'faces
+  :group 'yaml)
+
+(defcustom yaml-imenu-generic-expression
+  '((nil  "^\\(:?[a-zA-Z_-]+\\):"          1))
+  "The imenu regex to parse an outline of the yaml file."
+  :type 'string
+  :group 'yaml)
+
+
+;; Constants
+
+(defconst yaml-mode-version "0.0.13" "Version of `yaml-mode'.")
+
+(defconst yaml-blank-line-re "^ *$"
+  "Regexp matching a line containing only (valid) whitespace.")
+
+(defconst yaml-directive-re "^\\(?:--- \\)? *%\\(\\w+\\)"
+  "Regexp matching a line contatining a YAML directive.")
+
+(defconst yaml-document-delimiter-re "^ *\\(?:---\\|[.][.][.]\\)"
+  "Rexexp matching a YAML document delimiter line.")
+
+(defconst yaml-node-anchor-alias-re "[&*][a-zA-Z0-9_-]+"
+  "Regexp matching a YAML node anchor or alias.")
+
+(defconst yaml-tag-re "!!?[^ \n]+"
+  "Rexexp matching a YAML tag.")
+
+(defconst yaml-bare-scalar-re
+  "\\(?:[^-:,#!\n{\\[ ]\\|[^#!\n{\\[ ]\\S-\\)[^#\n]*?"
+  "Rexexp matching a YAML bare scalar.")
+
+(defconst yaml-hash-key-re
+  (concat "\\(?:^\\(?:--- \\)?\\|{\\|\\(?:[-,] +\\)+\\) *"
+          "\\(?:" yaml-tag-re " +\\)?"
+          "\\(" yaml-bare-scalar-re "\\) *:"
+          "\\(?: +\\|$\\)")
+  "Regexp matching a single YAML hash key.")
+
+(defconst yaml-scalar-context-re
+  (concat "\\(?:^\\(?:--- \\)?\\|{\\|\\(?: *[-,] +\\)+\\) *"
+          "\\(?:" yaml-bare-scalar-re " *: \\)?")
+  "Regexp indicating the beginning of a scalar context.")
+
+(defconst yaml-nested-map-re
+  (concat ".*: *\\(?:&.*\\|{ *\\|" yaml-tag-re " *\\)?$")
+  "Regexp matching a line beginning a YAML nested structure.")
+
+(defconst yaml-block-literal-base-re " *[>|][-+0-9]* *\\(?:\n\\|\\'\\)"
+  "Regexp matching the substring start of a block literal.")
+
+(defconst yaml-block-literal-re
+  (concat yaml-scalar-context-re
+          "\\(?:" yaml-tag-re "\\)?"
+          yaml-block-literal-base-re)
+  "Regexp matching a line beginning a YAML block literal.")
+
+(defconst yaml-nested-sequence-re
+  (concat "^\\(?:\\(?: *- +\\)+\\|\\(:? *-$\\)\\)"
+          "\\(?:" yaml-bare-scalar-re " *:\\(?: +.*\\)?\\)?$")
+  "Regexp matching a line containing one or more nested YAML sequences.")
+
+(defconst yaml-constant-scalars-re
+  (concat "\\(?:^\\|\\(?::\\|-\\|,\\|{\\|\\[\\) +\\) *"
+          (regexp-opt
+           '("~" "null" "Null" "NULL"
+             ".nan" ".NaN" ".NAN"
+             ".inf" ".Inf" ".INF"
+             "-.inf" "-.Inf" "-.INF"
+             "y" "Y" "yes" "Yes" "YES" "n" "N" "no" "No" "NO"
+             "true" "True" "TRUE" "false" "False" "FALSE"
+             "on" "On" "ON" "off" "Off" "OFF") t)
+          " *$")
+  "Regexp matching certain scalar constants in scalar context.")
+
+
+;; Mode setup
+
+(defvar yaml-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "|" 'yaml-electric-bar-and-angle)
+    (define-key map ">" 'yaml-electric-bar-and-angle)
+    (define-key map "-" 'yaml-electric-dash-and-dot)
+    (define-key map "." 'yaml-electric-dash-and-dot)
+    (define-key map (kbd "DEL") 'yaml-electric-backspace)
+    map)
+  "Keymap used in `yaml-mode' buffers.")
+
+(defvar yaml-mode-syntax-table
+  (let ((syntax-table (make-syntax-table)))
+    (modify-syntax-entry ?\' "\"" syntax-table)
+    (modify-syntax-entry ?\" "\"" syntax-table)
+    (modify-syntax-entry ?# "<" syntax-table)
+    (modify-syntax-entry ?\n ">" syntax-table)
+    (modify-syntax-entry ?\\ "\\" syntax-table)
+    (modify-syntax-entry ?- "_" syntax-table)
+    (modify-syntax-entry ?_ "_" syntax-table)
+    (modify-syntax-entry ?\( "." syntax-table)
+    (modify-syntax-entry ?\) "." syntax-table)
+    (modify-syntax-entry ?\{ "(}" syntax-table)
+    (modify-syntax-entry ?\} "){" syntax-table)
+    (modify-syntax-entry ?\[ "(]" syntax-table)
+    (modify-syntax-entry ?\] ")[" syntax-table)
+    syntax-table)
+  "Syntax table in use in `yaml-mode' buffers.")
+
+;;;###autoload
+(define-derived-mode yaml-mode text-mode "YAML"
+  "Simple mode to edit YAML.
+
+\\{yaml-mode-map}"
+  :syntax-table yaml-mode-syntax-table
+  (set (make-local-variable 'comment-start) "# ")
+  (set (make-local-variable 'comment-start-skip) "#+ *")
+  (set (make-local-variable 'indent-line-function) 'yaml-indent-line)
+  (set (make-local-variable 'indent-tabs-mode) nil)
+  (set (make-local-variable 'fill-paragraph-function) 'yaml-fill-paragraph)
+
+  (set (make-local-variable 'syntax-propertize-function)
+       'yaml-mode-syntax-propertize-function)
+  (setq font-lock-defaults '(yaml-font-lock-keywords)))
+
+
+;; Font-lock support
+
+(defvar yaml-font-lock-keywords
+  `((,yaml-constant-scalars-re . (1 font-lock-constant-face))
+    (,yaml-tag-re . (0 font-lock-type-face))
+    (,yaml-node-anchor-alias-re . (0 font-lock-function-name-face))
+    (,yaml-hash-key-re . (1 font-lock-variable-name-face))
+    (,yaml-document-delimiter-re . (0 font-lock-comment-face))
+    (,yaml-directive-re . (1 font-lock-builtin-face))
+    (yaml-font-lock-block-literals 0 font-lock-string-face)
+    ("^[\t]+" 0 'yaml-tab-face t))
+   "Additional expressions to highlight in YAML mode.")
+
+(defun yaml-mode-syntax-propertize-function (beg end)
+  "Unhighlight foo#bar tokens between BEG and END."
+  (save-excursion
+    (goto-char beg)
+    (while (search-forward "#" end t)
+      (save-excursion
+        (forward-char -1)
+        ;; both ^# and [ \t]# are comments
+        (when (and (not (bolp))
+                   (not (memq (preceding-char) '(?\s ?\t))))
+          (put-text-property (point) (1+ (point))
+                             'syntax-table (string-to-syntax "_")))))))
+
+(defun yaml-font-lock-block-literals (bound)
+  "Find lines within block literals.
+Find the next line of the first (if any) block literal after point and
+prior to BOUND.  Returns the beginning and end of the block literal
+line in the match data, as consumed by `font-lock-keywords' matcher
+functions.  The function begins by searching backwards to determine
+whether or not the current line is within a block literal.  This could
+be time-consuming in large buffers, so the number of lines searched is
+artificially limitted to the value of
+`yaml-block-literal-search-lines'."
+  (if (eolp) (goto-char (1+ (point))))
+  (unless (or (eobp) (>= (point) bound))
+    (let ((begin (point))
+          (end (min (1+ (point-at-eol)) bound)))
+      (goto-char (point-at-bol))
+      (while (and (looking-at yaml-blank-line-re) (not (bobp)))
+        (forward-line -1))
+      (let ((nlines yaml-block-literal-search-lines)
+            (min-level (current-indentation)))
+      (forward-line -1)
+      (while (and (/= nlines 0)
+                  (/= min-level 0)
+                  (not (looking-at yaml-block-literal-re))
+                  (not (bobp)))
+        (set 'nlines (1- nlines))
+        (unless (looking-at yaml-blank-line-re)
+          (set 'min-level (min min-level (current-indentation))))
+        (forward-line -1))
+      (cond
+       ((and (< (current-indentation) min-level)
+             (looking-at yaml-block-literal-re))
+          (goto-char end) (set-match-data (list begin end)) t)
+         ((progn
+            (goto-char begin)
+            (re-search-forward (concat yaml-block-literal-re
+                                       " *\\(.*\\)\n")
+                               bound t))
+          (set-match-data (nthcdr 2 (match-data))) t))))))
+
+
+;; Indentation and electric keys
+
+(defun yaml-compute-indentation ()
+  "Calculate the maximum sensible indentation for the current line."
+  (save-excursion
+    (beginning-of-line)
+    (if (looking-at yaml-document-delimiter-re) 0
+      (forward-line -1)
+      (while (and (looking-at yaml-blank-line-re)
+                  (> (point) (point-min)))
+        (forward-line -1))
+      (+ (current-indentation)
+         (if (looking-at yaml-nested-map-re) yaml-indent-offset 0)
+         (if (looking-at yaml-nested-sequence-re) yaml-indent-offset 0)
+         (if (looking-at yaml-block-literal-re) yaml-indent-offset 0)))))
+
+(defun yaml-indent-line ()
+  "Indent the current line.
+The first time this command is used, the line will be indented to the
+maximum sensible indentation.  Each immediately subsequent usage will
+back-dent the line by `yaml-indent-offset' spaces.  On reaching column
+0, it will cycle back to the maximum sensible indentation."
+  (interactive "*")
+  (let ((ci (current-indentation))
+        (cc (current-column))
+        (need (yaml-compute-indentation)))
+    (save-excursion
+      (beginning-of-line)
+      (delete-horizontal-space)
+      (if (and (equal last-command this-command) (/= ci 0))
+          (indent-to (* (/ (- ci 1) yaml-indent-offset) yaml-indent-offset))
+        (indent-to need)))
+      (if (< (current-column) (current-indentation))
+          (forward-to-indentation 0))))
+
+(defun yaml-electric-backspace (arg)
+  "Delete characters or back-dent the current line.
+If invoked following only whitespace on a line, will back-dent to the
+immediately previous multiple of `yaml-indent-offset' spaces."
+  (interactive "*p")
+  (if (or (/= (current-indentation) (current-column)) (bolp))
+      (funcall yaml-backspace-function arg)
+    (let ((ci (current-column)))
+      (beginning-of-line)
+      (delete-horizontal-space)
+      (indent-to (* (/ (- ci (* arg yaml-indent-offset))
+                       yaml-indent-offset)
+                    yaml-indent-offset)))))
+
+(defun yaml-electric-bar-and-angle (arg)
+  "Insert the bound key and possibly begin a block literal.
+Inserts the bound key.  If inserting the bound key causes the current
+line to match the initial line of a block literal, then inserts the
+matching string from `yaml-block-literal-electric-alist', a newline,
+and indents appropriately."
+  (interactive "*P")
+  (self-insert-command (prefix-numeric-value arg))
+  (let ((extra-chars
+         (assoc last-command-event
+                yaml-block-literal-electric-alist)))
+    (cond
+     ((and extra-chars (not arg) (eolp)
+           (save-excursion
+             (beginning-of-line)
+             (looking-at yaml-block-literal-re)))
+      (insert (cdr extra-chars))
+      (newline-and-indent)))))
+
+(defun yaml-electric-dash-and-dot (arg)
+  "Insert the bound key and possibly de-dent line.
+Inserts the bound key.  If inserting the bound key causes the current
+line to match a document delimiter, de-dent the line to the left
+margin."
+  (interactive "*P")
+  (self-insert-command (prefix-numeric-value arg))
+  (save-excursion
+    (beginning-of-line)
+    (if (and (not arg) (looking-at yaml-document-delimiter-re))
+        (delete-horizontal-space))))
+
+(defun yaml-narrow-to-block-literal ()
+  "Narrow the buffer to block literal if the point is in it,
+otherwise do nothing."
+  (interactive)
+  (save-excursion
+    (goto-char (point-at-bol))
+    (while (and (looking-at-p yaml-blank-line-re) (not (bobp)))
+      (forward-line -1))
+    (let ((nlines yaml-block-literal-search-lines)
+	  (min-level (current-indentation))
+	  beg)
+      (forward-line -1)
+      (while (and (/= nlines 0)
+		  (/= min-level 0)
+		  (not (looking-at-p yaml-block-literal-re))
+		  (not (bobp)))
+	(set 'nlines (1- nlines))
+	(unless (looking-at-p yaml-blank-line-re)
+	  (set 'min-level (min min-level (current-indentation))))
+	(forward-line -1))
+      (when (and (< (current-indentation) min-level)
+		  (looking-at-p yaml-block-literal-re))
+	(set 'min-level (current-indentation))
+	(forward-line)
+	(setq beg (point))
+	(while (and (not (eobp))
+		    (or (looking-at-p yaml-blank-line-re)
+			(> (current-indentation) min-level)))
+	  (forward-line))
+	(narrow-to-region beg (point))))))
+
+(defun yaml-fill-paragraph (&optional justify region)
+  "Fill paragraph.
+This behaves as `fill-paragraph' except that filling does not
+cross boundaries of block literals."
+  (interactive "*P")
+  (save-restriction
+    (yaml-narrow-to-block-literal)
+    (let ((fill-paragraph-function nil))
+      (fill-paragraph justify region))))
+
+(defun yaml-set-imenu-generic-expression ()
+  (make-local-variable 'imenu-generic-expression)
+  (make-local-variable 'imenu-create-index-function)
+  (setq imenu-create-index-function 'imenu-default-create-index-function)
+  (setq imenu-generic-expression yaml-imenu-generic-expression))
+
+(add-hook 'yaml-mode-hook 'yaml-set-imenu-generic-expression)
+
+
+(defun yaml-mode-version ()
+  "Display version of `yaml-mode'."
+  (interactive)
+  (message "yaml-mode %s" yaml-mode-version)
+  yaml-mode-version)
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.\\(e?ya?\\|ra\\)ml\\'" . yaml-mode))
+
+(provide 'yaml-mode)
+
+;;; yaml-mode.el ends here