Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added markdown handling

  • Loading branch information...
commit 661bc29abd8b0c52e031505fc8bdd31d57b51d03 1 parent 8e968d6
@vsbuffalo authored
Showing with 2,029 additions and 0 deletions.
  1. +1 −0  .gitignore
  2. +2,021 −0 modes/markdown-mode.el
  3. +7 −0 settings/mode-settings.el
View
1  .gitignore
@@ -10,3 +10,4 @@ modes/slime
tramp
elpa/*
.org*
+*.elc
View
2,021 modes/markdown-mode.el
@@ -0,0 +1,2021 @@
+;;; markdown-mode.el --- Emacs Major mode for Markdown-formatted text files
+
+;; Copyright (C) 2007-2011 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>
+
+;; Author: Jason R. Blevins <jrblevin@sdf.org>
+;; Maintainer: Jason R. Blevins <jrblevin@sdf.org>
+;; Created: May 24, 2007
+;; Version: 1.8.1
+;; 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 1.8.1, released on August 15, 2011:
+;;
+;; * [markdown-mode.el][]
+;; * [Screenshot][]
+;; * [Release notes][]
+;;
+;; [markdown-mode.el]: http://jblevins.org/projects/markdown-mode/markdown-mode.el
+;; [screenshot]: http://jblevins.org/projects/markdown-mode/screenshots/20110812-001.png
+;; [release notes]: http://jblevins.org/projects/markdown-mode/rev-1-8-1
+;;
+;; markdown-mode is also available in several package managers, including:
+;;
+;; * Debian and Ubuntu Linux: [emacs-goodies-el][]
+;; * RedHat and Fedora Linux: [emacs-goodies][]
+;; * OpenBSD: [textproc/markdown-mode][]
+;; * Arch Linux (AUR): [emacs-markdown-mode-git][]
+;;
+;; [emacs-goodies-el]: http://packages.debian.org/emacs-goodies-el
+;; [emacs-goodies]: https://admin.fedoraproject.org/pkgdb/acls/name/emacs-goodies
+;; [textproc/markdown-mode]: http://pkgsrc.se/textproc/markdown-mode
+;; [emacs-markdown-mode-git]: http://aur.archlinux.org/packages.php?ID=30389
+;;
+;; The latest development version can be downloaded directly
+;; ([markdown-mode.el][devel.el]) or it can be obtained from the
+;; (browsable and clonable) Git repository at
+;; <http://jblevins.org/git/markdown-mode.git>. The entire repository,
+;; including the full project history, can be cloned via the Git protocol
+;; by running
+;;
+;; git clone git://jblevins.org/git/markdown-mode.git
+;;
+;; [devel.el]: http://jblevins.org/git/markdown-mode.git/plain/markdown-mode.el
+
+;;; Dependencies:
+
+;; markdown-mode requires easymenu, a standard package since GNU Emacs
+;; 19 and XEmacs 19, which provides a uniform interface for creating
+;; menus in GNU Emacs and XEmacs.
+
+;;; 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` files:
+;;
+;; (autoload 'markdown-mode "markdown-mode.el"
+;; "Major mode for editing Markdown files" t)
+;; (setq auto-mode-alist
+;; (cons '("\\.text" . markdown-mode) auto-mode-alist))
+;;
+;; There is no consensus on an official file extension so change `.text` to
+;; `.mdwn`, `.md`, `.mdt`, or whatever you call your markdown files.
+
+;;; 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, but
+;; this command must accept input from `stdin`. If it does not, a
+;; simple wrapper script can be used to write `stdin` to a file
+;; and then pass that file to your Markdown interpreter. Ideally,
+;; this command will produce an XHTML fragment around which
+;; markdown-mode will wrap a header and footer (which can be
+;; further customized). However, it attempts to detect whether
+;; the command produces standalone XHTML output (via
+;; `markdown-xhtml-standalone-regexp'), in which case no header
+;; and footer content will be added.
+;;
+;; * `markdown-command-needs-filename' - set to non-nil if
+;; `markdown-command' does not accept input from stdin (default: nil).
+;; 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.
+;;
+;; * `markdown-hr-string' - string to use when inserting horizontal
+;; rules (default: `* * * * *').
+;;
+;; * `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-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-follow-wiki-link-on-enter' - set to a non-nil value
+;; to automatically open a linked document in a new buffer if the
+;; cursor is an wiki link
+;; (default: `t')
+;;
+;; * `markdown-uri-types' - a list of protocols for URIs that
+;; `markdown-mode' should highlight.
+;;
+;; * `markdown-enable-math' - syntax highlighting for
+;; LaTeX fragments (default: `nil').
+;;
+;; * `markdown-css-path' - CSS file to link to in XHTML output.
+;;
+;; * `markdown-xhtml-header-content' - additional content to include
+;; in the XHTML `<head>` block.
+;;
+;; * `markdown-xhtml-standalone-regexp' - a regular expression which
+;; indicates whether the output of `markdown-command' is standalone
+;; XHTML (default: `^\\(\<\?xml\\|\<!DOCTYPE\\|\<html\\)`). If
+;; this is not matched, we assume this output is a fragment and add
+;; our own header and footer.
+;;
+;; 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.
+
+;;; Usage:
+
+;; Keybindings are grouped by prefixes based on their function. For
+;; example, commands dealing with headers begin with `C-c C-t`. The
+;; primary commands in each group will are described below. You can
+;; obtain a list of all keybindings by pressing `C-c C-h`.
+;;
+;; * Anchors: `C-c C-a`
+;;
+;; `C-c C-a l` inserts inline links of the form `[text](url)`. If
+;; there is an active region, text in the region is used for the
+;; link text. `C-c C-a w` acts similarly for wiki links of the
+;; form `[[WikiLink]]`.
+;;
+;; * Commands: `C-c C-c`
+;;
+;; `C-c C-c m` will run Markdown on the current buffer and preview
+;; the output in another buffer while `C-c C-c p` runs Markdown on
+;; the current buffer and previews the output in a browser.
+;; `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. **This
+;; file will be overwritten without notice.** Press `C-c C-c v`
+;; to view the exported file in a browser.
+;;
+;; `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.
+;;
+;; * Images: `C-c C-i`
+;;
+;; `C-c C-i i` inserts an image, using the active region (if any)
+;; as the alt text.
+;;
+;; * Physical styles: `C-c C-p`
+;;
+;; These commands all act on text in the active region, if any,
+;; and insert empty markup fragments otherwise. `C-c C-p b` makes
+;; the selected text bold, `C-c C-p f` formats the region as
+;; fixed-width text, and `C-c C-p i` is used for italic text.
+;;
+;; * Logical styles: `C-c C-s`
+;;
+;; These commands all act on text in the active region, if any,
+;; and insert empty markup fragments otherwise. Logical styles
+;; include blockquote (`C-c C-s b`), preformatted (`C-c C-s p`),
+;; code (`C-c C-s c`), emphasis (`C-c C-s e`), and strong
+;; (`C-c C-s s`).
+;;
+;; * Headers: `C-c C-t`
+;;
+;; All header commands use text in the active region, if any, as
+;; the header text. To insert an atx or hash style level-n
+;; header, press `C-c C-t n` where n is between 1 and 6. For a
+;; top-level setext or underline style header press `C-c C-t t`
+;; (mnemonic: title) and for a second-level underline-style header
+;; press `C-c C-t s` (mnemonic: section).
+;;
+;; * Other elements:
+;;
+;; `C-c -` inserts a horizontal rule.
+;;
+;; * Wiki-Link Navigation:
+;;
+;; Use `M-p` and `M-n` to quickly jump to the previous and next
+;; wiki links, respectively.
+;;
+;; * Outline Navigation:
+;;
+;; Navigation between headings is possible using `outline-mode'.
+;; Use `C-M-n` and `C-M-p` to move between the next and previous
+;; visible headings. Similarly, `C-M-f` and `C-M-b` move to the
+;; next and previous visible headings at the same level as the one
+;; at the point. Finally, `C-M-u` will move up to a lower-level
+;; (more inclusive) visible heading.
+;;
+;; Many of the commands described above behave differently depending on
+;; whether Transient Mark mode is enabled or not. When it makes sense,
+;; if Transient Mark mode is on and a region is active, the command
+;; applies to the text in the region (e.g., `C-c C-p b` makes the region
+;; bold). For users who prefer to work outside of Transient Mark mode,
+;; in Emacs 22 it can be enabled temporarily by pressing `C-SPC C-SPC`.
+;;
+;; When applicable, commands that specifically act on the region even
+;; outside of Transient Mark mode have the same keybinding as the with
+;; the exception of an additional `C-` prefix. 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 C-b` and always applies to the region (when
+;; nonempty).
+;;
+;; 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.
+;;
+;; markdown-mode supports outline-minor-mode as well as org-mode-style
+;; visibility cycling for atx- or hash-style headers. There are two
+;; types of visibility cycling: Pressing `S-TAB` cycles globally between
+;; the table of contents view (headers only), outline view (top-level
+;; headers only), and the full document view. Pressing `TAB` while the
+;; point is at a header will cycle through levels of visibility for the
+;; subtree: completely folded, visible children, and fully visible.
+;; Note that mixing hash and underline style headers will give undesired
+;; results.
+
+;;; Extensions:
+
+;; Besides supporting the basic Markdown syntax, markdown-mode also
+;; includes syntax highlighting for `[[Wiki Links]]` by default. Wiki
+;; links may be followed automatically by hitting the enter key when
+;; your curser is on a wiki link or by hitting `C-c C-f`. The
+;; autofollowing on enter key may be controlled with the
+;; `markdown-follow-wiki-link-on-enter' customization. Use `M-p` and
+;; `M-n` to quickly jump to the previous and next wiki links,
+;; respectively. Aliased or piped wiki links of the form
+;; `[[PageName|link text]]` are also supported.
+;;
+;; [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:
+;;
+;; (defun markdown-custom ()
+;; "markdown-mode-hook"
+;; (setq markdown-command "markdown | smartypants"))
+;; (add-hook 'markdown-mode-hook '(lambda() (markdown-custom)))
+;;
+;; [SmartyPants]: http://daringfireball.net/projects/smartypants/
+;;
+;; Experimental 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-itex t)`
+;; in `.emacs`, and restarting Emacs.
+;;
+;; A [GitHub Flavored Markdown](http://github.github.com/github-flavored-markdown/)
+;; mode, `gfm-mode', is also available. The GitHub implementation of
+;; differs slightly from standard Markdown. Most importantly, newlines are
+;; significant and trigger hard line breaks. As such, `gfm-mode' turns off
+;; `auto-fill-mode' and turns on `longlines-mode'.
+
+;;; 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 reference checking functions.
+;; * 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.
+;; * Alec Resnick <alec@sproutward.org> for bug reports.
+;; * Joost Kremers <j.kremers@em.uni-frankfurt.de> for bug reports
+;; regarding indentation.
+;; * 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.
+
+;;; Bugs:
+
+;; Although markdown-mode is developed and tested primarily using
+;; GNU Emacs 24, compatibility with earlier Emacsen is also a
+;; priority.
+;;
+;; If you find any bugs in markdown-mode, please construct a test case
+;; or a patch and email me at <jrblevin@sdf.org>.
+
+;;; 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
+;; * 2008-05-24: [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][]
+;;
+;; [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
+
+
+;;; Code:
+
+(require 'easymenu)
+(require 'outline)
+(require 'cl)
+
+;;; Constants =================================================================
+
+(defconst markdown-mode-version "1.8.1"
+ "Markdown mode version number.")
+
+(defconst markdown-output-buffer-name "*markdown-output*"
+ "Name of temporary buffer for markdown command output.")
+
+;;; Customizable variables ====================================================
+
+(defvar markdown-mode-hook nil
+ "Hook runs when Markdown mode is loaded.")
+
+(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-hr-string "* * * * *"
+ "String to use for horizonal rules."
+ :group 'markdown
+ :type 'string)
+
+(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-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."
+ :group 'markdown
+ :type 'boolean)
+
+(defcustom markdown-follow-wiki-link-on-enter t
+ "Follow wiki link at point (if any) when the enter key is pressed."
+ :group 'markdown
+ :type 'boolean)
+
+(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 expressions.
+This will not take effect until Emacs is restarted."
+ :group 'markdown
+ :type 'boolean)
+
+(defcustom markdown-css-path ""
+ "URL of CSS file to link to in the output XHTML."
+ :group 'markdown
+ :type 'string)
+
+(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)
+
+;;; 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-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-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-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-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.")
+
+(defgroup markdown-faces nil
+ "Faces used in Markdown Mode"
+ :group 'markdown
+ :group 'faces)
+
+(defface markdown-italic-face
+ '((t :inherit font-lock-variable-name-face :italic t))
+ "Face for italic text."
+ :group 'markdown-faces)
+
+(defface markdown-bold-face
+ '((t :inherit font-lock-variable-name-face :bold t))
+ "Face for bold text."
+ :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 font-lock-builtin-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-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 font-lock-type-face))
+ "Face for link references."
+ :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-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)
+
+(defconst markdown-regex-link-inline
+ "\\(!?\\[[^]]*?\\]\\)\\(([^\\)]*)\\)"
+ "Regular expression for a [text](file) or an image link ![text](file).")
+
+(defconst markdown-regex-link-reference
+ "\\(!?\\[[^]]+?\\]\\)[ ]?\\(\\[[^]]*?\\]\\)"
+ "Regular expression for a reference link [text][id].")
+
+(defconst markdown-regex-reference-definition
+ "^ \\{0,3\\}\\(\\[.+?\\]\\):\\s *\\(.*?\\)\\s *\\( \"[^\"]*\"$\\|$\\)"
+ "Regular expression for a link definition [id]: ...")
+
+(defconst markdown-regex-header-1-atx
+ "^\\(# \\)\\(.*?\\)\\($\\| #+$\\)"
+ "Regular expression for level 1 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-2-atx
+ "^\\(## \\)\\(.*?\\)\\($\\| #+$\\)"
+ "Regular expression for level 2 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-3-atx
+ "^\\(### \\)\\(.*?\\)\\($\\| #+$\\)"
+ "Regular expression for level 3 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-4-atx
+ "^\\(#### \\)\\(.*?\\)\\($\\| #+$\\)"
+ "Regular expression for level 4 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-5-atx
+ "^\\(##### \\)\\(.*?\\)\\($\\| #+$\\)"
+ "Regular expression for level 5 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-6-atx
+ "^\\(###### \\)\\(.*?\\)\\($\\| #+$\\)"
+ "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-hr
+ "^\\(\\*[ ]?\\*[ ]?\\*[ ]?[\\* ]*\\|-[ ]?-[ ]?-[--- ]*\\)$"
+ "Regular expression for matching Markdown horizontal rules.")
+
+(defconst markdown-regex-code
+ "\\(^\\|[^\\]\\)\\(\\(`\\{1,2\\}\\)\\([^ \\]\\|[^ ]\\(.\\|\n[^\n]\\)*?[^ \\]\\)\\3\\)"
+ "Regular expression for matching inline code fragments.")
+
+(defconst markdown-regex-pre
+ "^\\( \\|\t\\).*$"
+ "Regular expression for matching preformatted text sections.")
+
+(defconst markdown-regex-list
+ "^[ \t]*\\([0-9]+\\.\\|[\\*\\+-]\\) "
+ "Regular expression for matching list markers.")
+
+(defconst markdown-regex-bold
+ "\\(^\\|[^\\]\\)\\(\\([*_]\\{2\\}\\)\\(.\\|\n[^\n]\\)*?[^\\ ]\\3\\)"
+ "Regular expression for matching bold text.")
+
+(defconst markdown-regex-italic
+ "\\(^\\|[^\\]\\)\\(\\([*_]\\)\\([^ \\]\\3\\|[^ ]\\(.\\|\n[^\n]\\)*?[^\\ ]\\3\\)\\)"
+ "Regular expression for matching italic text.")
+
+(defconst markdown-regex-blockquote
+ "^>.*$"
+ "Regular expression for matching blockquote lines.")
+
+(defconst markdown-regex-line-break
+ " $"
+ "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]]. In this regular
+expression, #1 matches the page name and #3 matches the link
+text.")
+
+(defconst markdown-regex-uri
+ (concat
+ "\\(" (mapconcat 'identity markdown-uri-types "\\|")
+ "\\):[^]\t\n\r<>,;() ]+")
+ "Regular expression for matching inline URIs.")
+
+(defconst markdown-regex-angle-uri
+ (concat
+ "\\(<\\)\\("
+ (mapconcat 'identity 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-latex-expression
+ "\\(^\\|[^\\]\\)\\(\\$\\($\\([^\\$]\\|\\\\.\\)*\\$\\|\\([^\\$]\\|\\\\.\\)*\\)\\$\\)"
+ "Regular expression for itex $..$ or $$..$$ math mode expressions.")
+
+(defconst markdown-regex-latex-display
+ "^\\\\\\[\\(.\\|\n\\)*?\\\\\\]$"
+ "Regular expression for itex \[..\] display mode expressions.")
+
+(defconst markdown-regex-list-indent
+ "^\\(\\s *\\)\\([0-9]+\\.\\|[\\*\\+-]\\)\\(\\s +\\)"
+ "Regular expression for matching indentation of list items.")
+
+(defvar markdown-mode-font-lock-keywords-basic
+ (list
+ '(markdown-match-pre-blocks 0 markdown-pre-face t t)
+ (cons markdown-regex-blockquote 'markdown-blockquote-face)
+ (cons markdown-regex-header-1-setext 'markdown-header-face-1)
+ (cons markdown-regex-header-2-setext 'markdown-header-face-2)
+ (cons markdown-regex-header-1-atx 'markdown-header-face-1)
+ (cons markdown-regex-header-2-atx 'markdown-header-face-2)
+ (cons markdown-regex-header-3-atx 'markdown-header-face-3)
+ (cons markdown-regex-header-4-atx 'markdown-header-face-4)
+ (cons markdown-regex-header-5-atx 'markdown-header-face-5)
+ (cons markdown-regex-header-6-atx 'markdown-header-face-6)
+ (cons markdown-regex-hr 'markdown-header-face)
+ '(markdown-match-comments 0 markdown-comment-face t t)
+ (cons markdown-regex-code '(2 markdown-inline-code-face))
+ (cons markdown-regex-list 'markdown-list-face)
+ (cons markdown-regex-link-inline
+ '((1 markdown-link-face t)
+ (2 markdown-url-face t)))
+ (cons markdown-regex-link-reference
+ '((1 markdown-link-face t)
+ (2 markdown-reference-face t)))
+ (cons markdown-regex-reference-definition
+ '((1 markdown-reference-face t)
+ (2 markdown-url-face t)
+ (3 markdown-link-title-face t)))
+ (cons markdown-regex-bold '(2 markdown-bold-face))
+ (cons markdown-regex-italic '(2 markdown-italic-face))
+ (cons markdown-regex-angle-uri 'markdown-link-face)
+ (cons markdown-regex-uri 'markdown-link-face)
+ (cons markdown-regex-email 'markdown-link-face)
+ )
+ "Syntax highlighting for Markdown files.")
+
+(defconst markdown-mode-font-lock-keywords-latex
+ (list
+ ;; Math mode $..$ or $$..$$
+ (cons markdown-regex-latex-expression '(2 markdown-math-face))
+ ;; Display mode equations with brackets: \[ \]
+ (cons markdown-regex-latex-display 'markdown-math-face)
+ ;; Equation reference (eq:foo)
+ (cons "(eq:\\w+)" 'markdown-reference-face)
+ ;; Equation reference \eqref{foo}
+ (cons "\\\\eqref{\\w+}" 'markdown-reference-face))
+ "Syntax highlighting for LaTeX fragments.")
+
+(defvar markdown-mode-font-lock-keywords
+ (append
+ (if markdown-enable-math
+ markdown-mode-font-lock-keywords-latex)
+ markdown-mode-font-lock-keywords-basic)
+ "Default highlighting expressions for Markdown mode.")
+
+
+
+;;; Markdown parsing functions ================================================
+
+(defun markdown-cur-line-blank-p ()
+ "Return t if the current line is blank and nil otherwise."
+ (save-excursion
+ (beginning-of-line)
+ (re-search-forward "^\\s *$" (point-at-eol) 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."
+ (save-excursion
+ (if (= (point-at-bol) (point-min))
+ t
+ (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
+ (forward-line -1)
+ (goto-char (point-at-bol))
+ (if (re-search-forward "^\\s " (point-at-eol) t) t)))
+
+(defun markdown-cur-line-indent ()
+ "Return the number of leading whitespace characters in the current line."
+ (save-excursion
+ (goto-char (point-at-bol))
+ (re-search-forward "^\\s +" (point-at-eol) t)
+ (current-column)))
+
+(defun markdown-prev-line-indent ()
+ "Return the number of leading whitespace characters in the previous line."
+ (save-excursion
+ (forward-line -1)
+ (markdown-cur-line-indent)))
+
+(defun markdown-cur-non-list-indent ()
+ "Return the number of leading whitespace characters in the current line."
+ (save-excursion
+ (beginning-of-line)
+ (when (re-search-forward markdown-regex-list-indent (point-at-eol) 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--next-block ()
+ "Move the point to the start of the next text block."
+ (forward-line)
+ (while (and (or (not (markdown-prev-line-blank-p))
+ (markdown-cur-line-blank-p))
+ (not (eobp)))
+ (forward-line)))
+
+(defun markdown--end-of-level (level)
+ "Move the point to the end of region with indentation at least LEVEL."
+ (let (indent)
+ (while (and (not (< (setq indent (markdown-cur-line-indent)) level))
+ (not (>= indent (+ level 4)))
+ (not (eobp)))
+ (markdown--next-block))
+ (unless (eobp)
+ ;; Move back before any trailing blank lines
+ (while (and (markdown-prev-line-blank-p)
+ (not (bobp)))
+ (forward-line -1))
+ (forward-line -1)
+ (end-of-line))))
+
+; From html-helper-mode
+(defun markdown-match-comments (last)
+ "Match HTML comments from the point to LAST."
+ (cond ((search-forward "<!--" last t)
+ (backward-char 4)
+ (let ((beg (point)))
+ (cond ((search-forward-regexp "--[ \t]*>" last t)
+ (set-match-data (list beg (point)))
+ t)
+ (t nil))))
+ (t nil)))
+
+(defun markdown-match-pre-blocks (last)
+ "Match Markdown pre blocks from point to LAST.
+A region matches as if it is indented at least four spaces
+relative to the nearest previous block of lesser non-list-marker
+indentation."
+
+ (let (cur-begin cur-end cur-indent prev-indent prev-list stop match found)
+ ;; Don't start in the middle of a block
+ (unless (and (bolp)
+ (markdown-prev-line-blank-p)
+ (not (markdown-cur-line-blank-p)))
+ (markdown--next-block))
+
+ ;; Move to the first full block in the region with indent 4 or more
+ (while (and (not (>= (setq cur-indent (markdown-cur-line-indent)) 4))
+ (not (>= (point) last)))
+ (markdown--next-block))
+ (setq cur-begin (point))
+ (markdown--end-of-level cur-indent)
+ (setq cur-end (point))
+ (setq match nil)
+ (setq stop (> cur-begin cur-end))
+
+ (while (and (<= cur-end last) (not stop) (not match))
+ ;; Move to the nearest preceding block of lesser (non-marker) indentation
+ (setq prev-indent (+ cur-indent 1))
+ (goto-char cur-begin)
+ (setq found nil)
+ (while (and (>= prev-indent cur-indent)
+ (not (and prev-list
+ (eq prev-indent cur-indent)))
+ (not (bobp)))
+
+ ;; Move point to the last line of the previous block.
+ (forward-line -1)
+ (while (and (markdown-cur-line-blank-p)
+ (not (bobp)))
+ (forward-line -1))
+
+ ;; Update the indentation level using either the
+ ;; non-list-marker indentation, if the previous line is the
+ ;; start of a list, or the actual indentation.
+ (setq prev-list (markdown-cur-non-list-indent))
+ (setq prev-indent (or prev-list
+ (markdown-cur-line-indent)))
+ (setq found t))
+
+ ;; If the loop didn't execute
+ (unless found
+ (setq prev-indent 0))
+
+ ;; Compare with prev-indent minus its remainder mod 4
+ (setq prev-indent (- prev-indent (mod prev-indent 4)))
+
+ ;; Set match data and return t if we have a match
+ (if (>= cur-indent (+ prev-indent 4))
+ ;; Match
+ (progn
+ (setq match t)
+ (set-match-data (list cur-begin cur-end))
+ ;; Leave point at end of block
+ (goto-char cur-end)
+ (forward-line))
+
+ ;; Move to the next block (if possible)
+ (goto-char cur-end)
+ (markdown--next-block)
+ (setq cur-begin (point))
+ (setq cur-indent (markdown-cur-line-indent))
+ (markdown--end-of-level cur-indent)
+ (setq cur-end (point))
+ (setq stop (equal cur-begin cur-end))))
+ match))
+
+(defun markdown-font-lock-extend-region ()
+ "Extend the search region to include an entire block of text.
+This helps improve font locking for block constructs such as pre blocks."
+ ;; Avoid compiler warnings about these global variables from font-lock.el.
+ ;; See the documentation for variable `font-lock-extend-region-functions'.
+ (eval-when-compile (defvar font-lock-beg) (defvar font-lock-end))
+ (save-excursion
+ (goto-char font-lock-beg)
+ (let ((found (re-search-backward "\n\n" nil t)))
+ (when found
+ (goto-char font-lock-end)
+ (when (re-search-forward "\n\n" nil t)
+ (beginning-of-line)
+ (setq font-lock-end (point)))
+ (setq font-lock-beg found)))))
+
+
+
+;;; Syntax Table ==============================================================
+
+(defvar markdown-mode-syntax-table
+ (let ((markdown-mode-syntax-table (make-syntax-table)))
+ (modify-syntax-entry ?\" "w" markdown-mode-syntax-table)
+ markdown-mode-syntax-table)
+ "Syntax table for `markdown-mode'.")
+
+
+
+;;; Element Insertion =========================================================
+
+(defun markdown-wrap-or-insert (s1 s2)
+ "Insert the strings S1 and S2.
+If Transient Mark mode is on and a region is active, wrap the strings S1
+and S2 around the region."
+ (if (and transient-mark-mode mark-active)
+ (let ((a (region-beginning)) (b (region-end)))
+ (goto-char a)
+ (insert s1)
+ (goto-char (+ b (length s1)))
+ (insert s2))
+ (insert s1 s2)))
+
+(defun markdown-insert-hr ()
+ "Insert a horizonal rule using `markdown-hr-string'."
+ (interactive)
+ ;; Leading blank line
+ (when (and (>= (point) (+ (point-min) 2))
+ (not (looking-back "\n\n" 2)))
+ (insert "\n"))
+ ;; Insert custom HR string
+ (insert (concat markdown-hr-string "\n"))
+ ;; Following blank line
+ (backward-char)
+ (unless (looking-at "\n\n")
+ (insert "\n")))
+
+(defun markdown-insert-bold ()
+ "Insert markup for a bold word or phrase.
+If Transient Mark mode is on and a region is active, it is made bold."
+ (interactive)
+ (if markdown-bold-underscore
+ (markdown-wrap-or-insert "__" "__")
+ (markdown-wrap-or-insert "**" "**"))
+ (backward-char 2))
+
+(defun markdown-insert-italic ()
+ "Insert markup for an italic word or phrase.
+If Transient Mark mode is on and a region is active, it is made italic."
+ (interactive)
+ (if markdown-italic-underscore
+ (markdown-wrap-or-insert "_" "_")
+ (markdown-wrap-or-insert "*" "*"))
+ (backward-char 1))
+
+(defun markdown-insert-code ()
+ "Insert markup for an inline code fragment.
+If Transient Mark mode is on and a region is active, it is marked
+as inline code."
+ (interactive)
+ (markdown-wrap-or-insert "`" "`")
+ (backward-char 1))
+
+(defun markdown-insert-link ()
+ "Insert an inline link of the form []().
+If Transient Mark mode is on and a region is active, it is used
+as the link text."
+ (interactive)
+ (markdown-wrap-or-insert "[" "]")
+ (insert "()")
+ (backward-char 1))
+
+(defun markdown-insert-wiki-link ()
+ "Insert a wiki link of the form [[WikiLink]].
+If Transient Mark mode is on and a region is active, it is used
+as the link text."
+ (interactive)
+ (markdown-wrap-or-insert "[[" "]]")
+ (backward-char 2))
+
+(defun markdown-insert-image ()
+ "Insert an inline image tag of the form ![]().
+If Transient Mark mode is on and a region is active, it is used
+as the alt text of the image."
+ (interactive)
+ (markdown-wrap-or-insert "![" "]")
+ (insert "()")
+ (backward-char 1))
+
+(defun markdown-insert-header-1 ()
+ "Insert a first level atx-style (hash mark) header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+ (interactive)
+ (markdown-insert-header 1))
+
+(defun markdown-insert-header-2 ()
+ "Insert a second level atx-style (hash mark) header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+ (interactive)
+ (markdown-insert-header 2))
+
+(defun markdown-insert-header-3 ()
+ "Insert a third level atx-style (hash mark) header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+ (interactive)
+ (markdown-insert-header 3))
+
+(defun markdown-insert-header-4 ()
+ "Insert a fourth level atx-style (hash mark) header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+ (interactive)
+ (markdown-insert-header 4))
+
+(defun markdown-insert-header-5 ()
+ "Insert a fifth level atx-style (hash mark) header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+ (interactive)
+ (markdown-insert-header 5))
+
+(defun markdown-insert-header-6 ()
+ "Insert a sixth level atx-style (hash mark) header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+ (interactive)
+ (markdown-insert-header 6))
+
+(defun markdown-insert-header (n)
+ "Insert an atx-style (hash mark) header.
+With no prefix argument, insert a level-1 header. With prefix N,
+insert a level-N header. If Transient Mark mode is on and the
+region is active, it is used as the header text."
+ (interactive "p")
+ (unless n ; Test to see if n is defined
+ (setq n 1)) ; Default to level 1 header
+ (let (hdr hdrl hdrr)
+ (dotimes (count n hdr)
+ (setq hdr (concat "#" hdr))) ; Build a hash mark header string
+ (setq hdrl (concat hdr " "))
+ (setq hdrr (concat " " hdr))
+ (markdown-wrap-or-insert hdrl hdrr))
+ (backward-char (+ 1 n)))
+
+(defun markdown-insert-title ()
+ "Insert a setext-style (underline) first level header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+ (interactive)
+ (if (and transient-mark-mode mark-active)
+ (let ((a (region-beginning))
+ (b (region-end))
+ (len 0)
+ (hdr))
+ (setq len (- b a))
+ (dotimes (count len hdr)
+ (setq hdr (concat "=" hdr))) ; Build a === title underline
+ (end-of-line)
+ (insert "\n" hdr "\n"))
+ (insert "\n==========\n")
+ (backward-char 12)))
+
+(defun markdown-insert-section ()
+ "Insert a setext-style (underline) second level header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+ (interactive)
+ (if (and transient-mark-mode mark-active)
+ (let ((a (region-beginning))
+ (b (region-end))
+ (len 0)
+ (hdr))
+ (setq len (- b a))
+ (dotimes (count len hdr)
+ (setq hdr (concat "-" hdr))) ; Build a --- section underline
+ (end-of-line)
+ (insert "\n" hdr "\n"))
+ (insert "\n----------\n")
+ (backward-char 12)))
+
+(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 (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
+ (markdown-blockquote-region (region-beginning) (region-end))
+ (insert "> ")))
+
+(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."
+ (if mark-active
+ (save-excursion
+ ;; Ensure that there is a leading blank line
+ (goto-char beg)
+ (when (and (>= (point) (+ (point-min) 2))
+ (not (looking-back "\n\n" 2)))
+ (insert "\n")
+ (setq beg (1+ beg))
+ (setq end (1+ end)))
+ ;; Move back before any blank lines at the end
+ (goto-char end)
+ (while (and (looking-back "\n" 1)
+ (not (equal (point) (point-min))))
+ (backward-char)
+ (setq end (1- end)))
+ ;; Ensure that there is a trailing blank line
+ (goto-char end)
+ (if (not (or (looking-at "\n\n")
+ (and (equal (1+ end) (point-max)) (looking-at "\n"))))
+ (insert "\n"))
+ ;; Insert PREFIX
+ (goto-char beg)
+ (beginning-of-line)
+ (while (< (point-at-bol) end)
+ (insert prefix)
+ (setq end (+ (length prefix) end))
+ (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 "> "))
+
+(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 (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
+ (markdown-pre-region (region-beginning) (region-end))
+ (insert " ")))
+
+(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")
+ (markdown-block-region beg end " "))
+
+;;; Indentation ====================================================================
+
+(defun markdown-indent-find-next-position (cur-pos positions)
+ "Return the position after the index of CUR-POS in POSITIONS."
+ (while (and positions
+ (not (equal cur-pos (car positions))))
+ (setq positions (cdr positions)))
+ (or (cadr positions) 0))
+
+(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."
+ (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."
+ (let (pos prev-line-pos positions)
+
+ ;; Previous line indent
+ (setq prev-line-pos (markdown-prev-line-indent))
+ (setq positions (cons prev-line-pos positions))
+
+ ;; Previous non-list-marker indent
+ (setq pos (markdown-prev-non-list-indent))
+ (if pos
+ (setq positions (cons pos positions)))
+
+ ;; Indentation of the previous line + tab-width
+ (cond
+ (prev-line-pos
+ (setq positions (cons (+ prev-line-pos tab-width) positions)))
+ (t
+ (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 preceeding list item
+ (setq pos
+ (save-excursion
+ (forward-line -1)
+ (catch 'break
+ (while (not (equal (point) (point-min)))
+ (forward-line -1)
+ (goto-char (point-at-bol))
+ (when (re-search-forward markdown-regex-list-indent (point-at-eol) t)
+ (throw 'break (length (match-string 1)))))
+ nil)))
+ (if (and pos (not (eq pos prev-line-pos)))
+ (setq positions (cons pos positions)))
+
+ ;; First column
+ (setq positions (cons 0 positions))
+
+ (reverse positions)))
+
+(defun markdown-do-normal-return ()
+ "Insert a newline and optionally indent the next line."
+ (newline)
+ (if markdown-indent-on-enter
+ (funcall indent-line-function)))
+
+(defun markdown-enter-key ()
+ "Handle RET according to context.
+If there is a wiki link at the point, follow it unless
+`markdown-follow-wiki-link-on-enter' is nil. Otherwise, process
+it in the usual way."
+ (interactive)
+ (if (and markdown-follow-wiki-link-on-enter (markdown-wiki-link-p))
+ (markdown-follow-wiki-link-at-point)
+ (markdown-do-normal-return)))
+
+
+
+;;; 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-aw" 'markdown-insert-wiki-link)
+ (define-key map "\C-c\C-ii" 'markdown-insert-image)
+ (define-key map "\C-c\C-t1" 'markdown-insert-header-1)
+ (define-key map "\C-c\C-t2" 'markdown-insert-header-2)
+ (define-key map "\C-c\C-t3" 'markdown-insert-header-3)
+ (define-key map "\C-c\C-t4" 'markdown-insert-header-4)
+ (define-key map "\C-c\C-t5" 'markdown-insert-header-5)
+ (define-key map "\C-c\C-t6" 'markdown-insert-header-6)
+ (define-key map "\C-c\C-pb" 'markdown-insert-bold)
+ (define-key map "\C-c\C-ss" 'markdown-insert-bold)
+ (define-key map "\C-c\C-pi" 'markdown-insert-italic)
+ (define-key map "\C-c\C-se" 'markdown-insert-italic)
+ (define-key map "\C-c\C-pf" 'markdown-insert-code)
+ (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-" 'markdown-insert-hr)
+ (define-key map "\C-c\C-tt" 'markdown-insert-title)
+ (define-key map "\C-c\C-ts" 'markdown-insert-section)
+ ;; WikiLink Following
+ (define-key map "\C-c\C-f" 'markdown-follow-wiki-link-at-point)
+ (define-key map "\M-n" 'markdown-next-wiki-link)
+ (define-key map "\M-p" 'markdown-previous-wiki-link)
+ ;; Indentation
+ (define-key map "\C-m" 'markdown-enter-key)
+ ;; Visibility cycling
+ (define-key map (kbd "<tab>") 'markdown-cycle)
+ (define-key map (kbd "<S-iso-lefttab>") 'markdown-shifttab)
+ ;; Header navigation
+ (define-key map (kbd "C-M-n") 'outline-next-visible-heading)
+ (define-key map (kbd "C-M-p") 'outline-previous-visible-heading)
+ (define-key map (kbd "C-M-f") 'outline-forward-same-level)
+ (define-key map (kbd "C-M-b") 'outline-backward-same-level)
+ (define-key map (kbd "C-M-u") 'outline-up-heading)
+ ;; Markdown functions
+ (define-key map "\C-c\C-cm" 'markdown)
+ (define-key map "\C-c\C-cp" 'markdown-preview)
+ (define-key map "\C-c\C-ce" 'markdown-export)
+ (define-key map "\C-c\C-cv" 'markdown-export-and-view)
+ ;; References
+ (define-key map "\C-c\C-cc" 'markdown-check-refs)
+ map)
+ "Keymap for Markdown major mode.")
+
+;;; Menu ==================================================================
+
+(easy-menu-define markdown-mode-menu markdown-mode-map
+ "Menu for Markdown mode"
+ '("Markdown"
+ ("Show/Hide"
+ ["Cycle visibility" markdown-cycle (outline-on-heading-p)]
+ ["Cycle global visibility" markdown-shifttab])
+ "---"
+ ["Compile" markdown]
+ ["Preview" markdown-preview]
+ ["Export" markdown-export]
+ ["Export & View" markdown-export-and-view]
+ "---"
+ ("Headers (setext)"
+ ["Insert Title" markdown-insert-title]
+ ["Insert Section" markdown-insert-section])
+ ("Headers (atx)"
+ ["First level" markdown-insert-header-1]
+ ["Second level" markdown-insert-header-2]
+ ["Third level" markdown-insert-header-3]
+ ["Fourth level" markdown-insert-header-4]
+ ["Fifth level" markdown-insert-header-5]
+ ["Sixth level" markdown-insert-header-6])
+ "---"
+ ["Bold" markdown-insert-bold]
+ ["Italic" markdown-insert-italic]
+ ["Blockquote" markdown-insert-blockquote]
+ ["Preformatted" markdown-insert-pre]
+ ["Code" markdown-insert-code]
+ "---"
+ ["Insert inline link" markdown-insert-link]
+ ["Insert image" markdown-insert-image]
+ ["Insert horizontal rule" markdown-insert-hr]
+ "---"
+ ["Check references" markdown-check-refs]
+ "---"
+ ["Version" markdown-show-version]
+ ))
+
+
+
+;;; References ================================================================
+
+;;; Undefined reference checking code by Dmitry Dzhus <mail@sphinx.net.ru>.
+
+(defconst markdown-refcheck-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-has-reference-definition (reference)
+ "Find out whether Markdown REFERENCE is defined.
+
+REFERENCE should include the square brackets, like [this]."
+ (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 1)))
+ (throw 'found t)))))))
+
+(defun markdown-get-undefined-refs ()
+ "Return a list of undefined Markdown references.
+
+Result is an alist of pairs (reference . occurencies), where
+occurencies 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* ((label (match-string-no-properties 1))
+ (reference (match-string-no-properties 2))
+ (target (downcase (if (string= reference "[]") label reference))))
+ (unless (markdown-has-reference-definition target)
+ (let ((entry (assoc target missing)))
+ (if (not entry)
+ (add-to-list 'missing (cons target
+ (list (cons label (markdown-line-number-at-pos)))) t)
+ (setcdr entry
+ (append (cdr entry) (list (cons label (markdown-line-number-at-pos))))))))))
+ missing)))
+
+(defun markdown-add-missing-ref-definition (ref buffer &optional recheck)
+ "Add blank REF definition to the end of BUFFER.
+
+REF is a Markdown reference in square brackets, like \"[lisp-history]\".
+
+When RECHECK is non-nil, BUFFER gets rechecked for undefined
+references so that REF disappears from the list of those links."
+ (with-current-buffer buffer
+ (when (not (eq major-mode 'markdown-mode))
+ (error "Not available in current mode"))
+ (goto-char (point-max))
+ (indent-new-comment-line)
+ (insert (concat ref ": ")))
+ (switch-to-buffer-other-window buffer)
+ (goto-char (point-max))
+ (when recheck
+ (markdown-check-refs t)))
+
+;; Button which adds an empty Markdown reference definition to the end
+;; of buffer specified as its 'target-buffer property. Reference name
+;; is button's label
+(when (>= emacs-major-version 22)
+ (define-button-type 'markdown-ref-button
+ 'help-echo "Push to create an empty reference definition"
+ 'face 'bold
+ 'action (lambda (b)
+ (markdown-add-missing-ref-definition
+ (button-label b) (button-get b 'target-buffer) t))))
+
+;; Button jumping to line in buffer specified as its 'target-buffer
+;; property. Line number is button's 'line property.
+(when (>= emacs-major-version 22)
+ (define-button-type 'goto-line-button
+ 'help-echo "Push to go to this line"
+ '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
+ (call-interactively 'goto-line (button-get b 'target-line)))))
+
+(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 (get-buffer-create (replace-regexp-in-string
+ "%BUFFER%" (buffer-name)
+ markdown-refcheck-buffer t))))
+ (if (null refs)
+ (progn
+ (when (not silent)
+ (message "No undefined references found"))
+ (kill-buffer refbuf))
+ (with-current-buffer refbuf
+ (when view-mode
+ (View-exit-and-edit))
+ (erase-buffer)
+ (insert "Following references lack definitions:")
+ (newline 2)
+ (dolist (ref refs)
+ (let ((button-label (format "%s" (car ref))))
+ (if (>= emacs-major-version 22)
+ ;; Create a reference button in Emacs 22
+ (insert-text-button button-label
+ :type 'markdown-ref-button
+ 'target-buffer oldbuf)
+ ;; Insert reference as text in Emacs < 22
+ (insert button-label)))
+ (insert " (")
+ (dolist (occurency (cdr ref))
+ (let ((line (cdr occurency)))
+ (if (>= emacs-major-version 22)
+ ;; Create a line number button in Emacs 22
+ (insert-button (number-to-string line)
+ :type '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))
+ (view-buffer-other-window refbuf)
+ (goto-char (point-min))
+ (forward-line 2)))))
+
+;;; Outline ===================================================================
+
+;; The following visibility cycling code was taken from org-mode
+;; by Carsten Dominik and adapted for markdown-mode.
+
+(defvar markdown-cycle-global-status 1)
+(defvar markdown-cycle-subtree-status nil)
+
+;; Based on org-end-of-subtree from org.el
+(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."
+ (outline-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)
+ (outline-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))
+
+;; Based on org-cycle from org.el.
+(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'."
+ (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
+ (hide-sublevels 1)
+ (message "CONTENTS")
+ (setq markdown-cycle-global-status 3))
+
+ ((and (eq last-command this-command)
+ (eq markdown-cycle-global-status 3))
+ ;; Move from contents to all
+ (show-all)
+ (message "SHOW ALL")
+ (setq markdown-cycle-global-status 1))
+
+ (t
+ ;; Defaults to overview
+ (hide-body)
+ (message "OVERVIEW")
+ (setq markdown-cycle-global-status 2))))
+
+ ((save-excursion (beginning-of-line 1) (looking-at outline-regexp))
+ ;; At a heading: rotate between three different views
+ (outline-back-to-heading)
+ (let ((goal-column 0) eoh eol eos)
+ ;; Determine boundaries
+ (save-excursion
+ (outline-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)))
+ (outline-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
+ (show-entry)
+ (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.
+ (show-subtree)
+ (message "SUBTREE")
+ (setq markdown-cycle-subtree-status 'subtree))
+ (t
+ ;; Default action: hide the subtree.
+ (hide-subtree)
+ (message "FOLDED")
+ (setq markdown-cycle-subtree-status 'folded)))))
+
+ (t
+ (indent-for-tab-command))))
+
+;; Based on org-shifttab from org.el.
+(defun markdown-shifttab ()
+ "Global visibility cycling.
+Calls `markdown-cycle' with argument t."
+ (interactive)
+ (markdown-cycle t))
+
+;;; Commands ==================================================================
+
+(defun markdown (&optional output-buffer-name)
+ "Run `markdown' on current buffer and insert output in buffer BUFFER-OUTPUT."
+ (interactive)
+ (let ((title (buffer-name))
+ (begin-region)
+ (end-region))
+ (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
+ (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))
+
+ (if markdown-command-needs-filename
+ ;; Handle case when `markdown-command' does not read from stdin
+ (if (not buffer-file-name)
+ (error "Must be visiting a file")
+ (shell-command (concat markdown-command " " buffer-file-name)
+ output-buffer-name))
+ ;; Pass region to `markdown-command' via stdin
+ (shell-command-on-region begin-region end-region markdown-command
+ output-buffer-name))
+
+ ;; Add header and footer and switch to html-mode.
+ (save-current-buffer
+ (set-buffer output-buffer-name)
+ (goto-char (point-min))
+ (unless (markdown-output-standalone-p)
+ (markdown-add-xhtml-header-and-footer title))
+ (html-mode))
+
+ ;; Ensure buffer gets raised, even with short command output
+ (switch-to-buffer-other-window 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."
+ (re-search-forward
+ markdown-xhtml-standalone-regexp
+ (save-excursion (goto-char (point-min)) (forward-line 4) (point))
+ t))
+
+(defun markdown-add-xhtml-header-and-footer (title)
+ "Wrap XHTML header and footer with given TITLE around current buffer."
+ (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")
+ (if (> (length markdown-css-path) 0)
+ (insert "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\""
+ markdown-css-path
+ "\" />\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 ()
+ "Run `markdown' on the current buffer and preview the output in a browser."
+ (interactive)
+ (markdown markdown-output-buffer-name)
+ (browse-url-of-buffer markdown-output-buffer-name))
+
+(defun markdown-export-file-name ()
+ "Attempt to generate a filename for Markdown output.
+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)
+ (concat (file-name-sans-extension (buffer-file-name)) ".html")))
+
+(defun markdown-export ()
+ "Run Markdown on the current buffer, save to a file, and return the filename.
+The resulting filename will be constructed using the current filename, but
+with the extension removed and replaced with .html."
+ (interactive)
+ (let ((output-file (markdown-export-file-name))
+ (output-buffer-name))
+ (when output-file
+ (setq output-buffer-name (buffer-name (find-file-noselect output-file)))
+ (markdown output-buffer-name)
+ (with-current-buffer output-buffer-name
+ (save-buffer)
+ (kill-buffer-and-window))
+ output-file)))
+
+(defun markdown-export-and-view ()
+ "Export to XHTML using `markdown-export' and browse the resulting file."
+ (interactive)
+ (browse-url (markdown-export)))
+
+;;; WikiLink Following/Markup =================================================
+
+(require 'thingatpt)
+
+(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)
+ (or (not buffer-file-name)
+ (not (string-equal (buffer-file-name)
+ (markdown-convert-wiki-link-to-filename
+ (match-string 1)))))
+ (not (save-match-data
+ (save-excursion))))))
+
+(defun markdown-convert-wiki-link-to-filename (name)
+ "Generate a filename from the wiki link NAME.
+Spaces are converted to underscores, following the convention
+used by the Python Markdown WikiLinks extension."
+ (let ((new-ext (file-name-extension (buffer-file-name)))
+ (new-basename (replace-regexp-in-string "[[:space:]\n]" "_" name)))
+ (concat new-basename "." new-ext)))
+
+(defun markdown-follow-wiki-link (name)
+ "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'."
+ (let ((filename (markdown-convert-wiki-link-to-filename name)))
+ (find-file filename))
+ (markdown-mode))
+
+(defun markdown-follow-wiki-link-at-point ()
+ "Find Wiki Link at point.
+See `markdown-wiki-link-p' and `markdown-follow-wiki-link'."
+ (interactive)
+ (if (markdown-wiki-link-p)
+ (markdown-follow-wiki-link (match-string 1))
+ (error "Point is not at a Wiki Link")))
+
+(defun markdown-next-wiki-link ()
+ "Jump to next wiki link.
+See `markdown-wiki-link-p'."
+ (interactive)
+ (if (markdown-wiki-link-p)
+ ; At a wiki link already, move past it.
+ (goto-char (+ 1 (match-end 0))))
+ (save-match-data
+ ; Search for the next wiki link and move to the beginning.
+ (re-search-forward markdown-regex-wiki-link nil t)
+ (goto-char (match-beginning 0))))
+
+(defun markdown-previous-wiki-link ()
+ "Jump to previous wiki link.
+See `markdown-wiki-link-p'."
+ (interactive)
+ (re-search-backward markdown-regex-wiki-link nil t))
+
+(defun markdown-highlight-wiki-link (from to face)
+ "Highlight the wiki link in the region between FROM and TO using FACE."
+ (let ((ov (make-overlay from to)))
+ (overlay-put ov 'face face)))
+
+(defun markdown-unfontify-region-wiki-links (from to)
+ "Remove wiki link faces from the region specified by FROM and TO."
+ (interactive "nfrom: \nnto: ")
+ (remove-overlays from to 'face markdown-link-face)
+ (remove-overlays from to '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)
+ (while (re-search-forward markdown-regex-wiki-link to t)
+ (let ((highlight-beginning (match-beginning 0))
+ (highlight-end (match-end 0))
+ (file-name
+ (markdown-convert-wiki-link-to-filename (match-string 1))))
+ (if (file-exists-p file-name)
+ (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)))
+ (list new-from new-to)))
+
+(defun markdown-check-change-for-wiki-link (from to change)
+ "Check region between FROM and TO for wiki links and re-fontfy as needed.
+Designed to be used with the `after-change-functions' hook.
+CHANGE is the number of bytes of pre-change text replaced by the
+given range."
+ (interactive "nfrom: \nnto: \nnchange: ")
+ (let* ((inhibit-point-motion-hooks t)
+ (inhibit-quit t)
+ (modified (buffer-modified-p))
+ (buffer-undo-list t)
+ (inhibit-read-only t)
+ (inhibit-point-motion-hooks t)
+ (inhibit-modification-hooks t)
+ (current-point (point))
+ deactivate-mark)
+ (unwind-protect
+ (save-restriction
+ ;; Extend the region to fontify so that it starts
+ ;; and ends at safe places.
+ (multiple-value-bind (new-from new-to)
+ (markdown-extend-changed-region from to)
+ ;; 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)))
+ (unless modified
+ (restore-buffer-modified-p nil)))
+ (goto-char current-point)))
+
+(defun markdown-fontify-buffer-wiki-links ()
+ "Refontify all wiki links in the buffer."
+ (interactive)
+ (markdown-check-change-for-wiki-link (point-min) (point-max) 0))
+
+;;; Miscellaneous =============================================================
+
+(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-nobreak-p ()
+ "Return nil if it is acceptable to break the current line at the point."
+ ;; inside in square brackets (e.g., link anchor text)
+ (looking-back "\\[[^]]*"))
+
+
+
+;;; 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)
+ ;; Font lock.
+ (set (make-local-variable 'font-lock-defaults)
+ '(markdown-mode-font-lock-keywords))
+ (set (make-local-variable 'font-lock-multiline) t)
+ ;; For menu support in XEmacs
+ (easy-menu-add markdown-mode-menu markdown-mode-map)
+ ;; Make filling work with lists (unordered, ordered, and definition)
+ (set (make-local-variable 'paragraph-start)
+ "\f\\|[ \t]*$\\|^[ \t]*[*+-] \\|^[ \t*][0-9]+\\.\\|^[ \t]*: ")
+ ;; Outline mode
+ (make-local-variable 'outline-regexp)
+ (setq outline-regexp "#+")
+ ;; Cause use of ellipses for invisible text.
+ (add-to-invisibility-spec '(outline . t))
+ ;; Indentation and filling
+ (make-local-variable 'fill-nobreak-predicate)
+ (add-hook 'fill-nobreak-predicate 'markdown-nobreak-p)
+ (setq indent-line-function markdown-indent-function)
+
+ ;; 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))
+
+ ;; Multiline font lock
+ (add-hook 'font-lock-extend-region-functions
+ 'markdown-font-lock-extend-region)
+
+ ;; Anytime text changes make sure it gets fontified correctly
+ (add-hook 'after-change-functions 'markdown-check-change-for-wiki-link 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)
+
+ ;; do the initial link fontification
+ (markdown-fontify-buffer-wiki-links))
+
+;(add-to-list 'auto-mode-alist '("\\.text$" . markdown-mode))
+
+;;; GitHub Flavored Markdown Mode ============================================
+
+(define-derived-mode gfm-mode markdown-mode "GFM"
+ "Major mode for editing GitHub Flavored Markdown files."
+ (auto-fill-mode 0)
+ (longlines-mode 1))
+
+(provide 'markdown-mode)
+
+;;; markdown-mode.el ends here
View
7 settings/mode-settings.el
@@ -193,3 +193,10 @@
(add-to-list 'load-path
(concat *emacs-root* "modes/emacspeak/lisp/g-client/"))
(require 'g)
+
+;; ========= Markdown-mode =========
+;; More info here: http://jblevins.org/projects/markdown-mode/
+(autoload 'markdown-mode "markdown-mode.el" "Major mode for
+editing Markdown files" t)
+(setq auto-mode-alist (cons
+'("\\.md" . markdown-mode) auto-mode-alist))
Please sign in to comment.
Something went wrong with that request. Please try again.