diff --git a/init.el b/init.el index d07826c..bc657f3 100644 --- a/init.el +++ b/init.el @@ -16,6 +16,14 @@ (setq-default whitespace-line-column 80) (global-whitespace-mode 1) +;; Markdown http://jblevins.org/projects/markdown-mode/markdown-mode.el +(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)) +(add-to-list 'auto-mode-alist '("\\.mdwn\\'" . markdown-mode)) + ;; C, use k&r style by default (naev) (setq-default c-default-style "k&r" c-basic-offset 3) diff --git a/markdown-mode.el b/markdown-mode.el new file mode 100644 index 0000000..78b2965 --- /dev/null +++ b/markdown-mode.el @@ -0,0 +1,4669 @@ +;;; markdown-mode.el --- Emacs Major mode for Markdown-formatted text files + +;; Copyright (C) 2007-2013 Jason R. Blevins +;; Copyright (C) 2007, 2009 Edward O'Connor +;; Copyright (C) 2007 Conal Elliott +;; Copyright (C) 2008 Greg Bognar +;; Copyright (C) 2008 Dmitry Dzhus +;; Copyright (C) 2008 Bryan Kyle +;; Copyright (C) 2008 Ben Voui +;; Copyright (C) 2009 Ankit Solanki +;; Copyright (C) 2009 Hilko Bengen +;; Copyright (C) 2009 Peter Williams +;; Copyright (C) 2010 George Ogata +;; Copyright (C) 2011 Eric Merritt +;; Copyright (C) 2011 Philippe Ivaldi +;; Copyright (C) 2011 Jeremiah Dodds +;; Copyright (C) 2011 Christopher J. Madsen +;; Copyright (C) 2011 Shigeru Fukaya +;; Copyright (C) 2011 Joost Kremers +;; Copyright (C) 2011-2012 Donald Ephraim Curtis +;; Copyright (C) 2012 Akinori Musha +;; Copyright (C) 2012 Zhenlei Jia +;; Copyright (C) 2012 Peter Jones +;; Copyright (C) 2013 Matus Goljer + +;; Author: Jason R. Blevins +;; Maintainer: Jason R. Blevins +;; Created: May 24, 2007 +;; Version: 2.0 +;; 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.0, released on March 24, 2013: +;; +;; * [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/20130131-002.png +;; [release notes]: http://jblevins.org/projects/markdown-mode/rev-2-0 +;; +;; [^theme]: The theme used in the screenshot is +;; [color-theme-twilight](https://github.com/crafterm/twilight-emacs). +;; +;; 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][] +;; * MacPorts: [markdown-mode.el][macports-package] ([pending][macports-ticket]) +;; * FreeBSD: [textproc/markdown-mode.el][freebsd-port] +;; +;; [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 +;; [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 +;; +;; 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 +;; . 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 + +;;; 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. + +;;; 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 `` 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 `` 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 (``) and `C-c C-s c` for +;; inline 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. **For both export commands, the +;; output file will be overwritten without notice.** +;; *Open:* `C-c C-c o` will open the Markdown source file directly +;; using `markdown-open-command'. +;; +;; 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 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 +;; `

` to `

`) 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`. +;; +;; * 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][], a +;; live-updating MultiMarkdown previewer which has a command line +;; utility at `/usr/local/bin/mark`. +;; +;; * `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 +;; `
`--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-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-path' - CSS file to link to in XHTML output +;; (default: `""`). +;; +;; * `markdown-content-type' - when set to a nonempty string, an +;; `http-equiv` attribute will be included in the XHTML `` +;; 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 `` 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\\| for Debian packaging. +;; * Conal Elliott for a font-lock regexp patch. +;; * Edward O'Connor for a font-lock regexp fix and +;; GitHub Flavored Markdown mode (`gfm-mode'). +;; * Greg Bognar for menus and running +;; `markdown' with an active region. +;; * Daniel Burrows for filing Debian bug #456592. +;; * Peter S. Galbraith for maintaining `emacs-goodies-el`. +;; * Dmitry Dzhus for undefined reference checking. +;; * Carsten Dominik for `org-mode', from which the +;; visibility cycling functionality was derived, and for a bug fix +;; related to `orgtbl-mode'. +;; * Bryan Kyle for indentation code. +;; * Ben Voui for font-lock face customizations. +;; * Ankit Solanki for `longlines.el` +;; compatibility and custom CSS. +;; * Hilko Bengen for proper XHTML output. +;; * Jose A. Ortega Ruiz for Emacs 23 fixes. +;; * Nelson Minar for `html-helper-mode', from which +;; comment matching functions were derived. +;; * Alec Resnick for bug reports. +;; * Joost Kremers for footnote-handling +;; functions, bug reports regarding indentation, and +;; fixes for byte-compilation warnings. +;; * Peter Williams for `fill-paragraph' +;; enhancements. +;; * George Ogata for fixing several +;; byte-compilation warnings. +;; * Eric Merritt for wiki link features. +;; * Philippe Ivaldi for XHTML preview +;; customizations and XHTML export. +;; * Jeremiah Dodds for supporting +;; Markdown processors which do not accept input from stdin. +;; * Werner Dittmann for bug reports +;; regarding the `cl` dependency and `auto-fill-mode' and indentation. +;; * Scott Pfister for generalizing the space +;; substitution character for mapping wiki links to filenames. +;; * Marcin Kasperski for a patch to +;; escape shell commands. +;; * Christopher J. Madsen for patches to fix a match +;; data bug and to prefer `visual-line-mode' in `gfm-mode'. +;; * Shigeru Fukaya for better adherence to +;; Emacs Lisp coding conventions. +;; * Donald Ephraim Curtis for fixing the `fill-paragraph' +;; regexp, refactoring the compilation and preview functions, +;; heading font-lock generalizations, list renumbering, +;; and kill ring save. +;; * Kevin Porter for wiki link handling in `gfm-mode'. +;; * Max Penet and Peter Eisentraut +;; for an autoload token for `gfm-mode'. +;; * Ian Yang for improving the reference definition regex. +;; * Akinori Musha for an imenu index function. +;; * Michael Sperber for XEmacs fixes. +;; * Francois Gannaz for suggesting charset +;; declaration in XHTML output. +;; * Zhenlei Jia for smart exdention function. +;; * Matus Goljer for improved wiki link following +;; and GFM code block insertion. +;; * Peter Jones for link following functions. +;; * Bryan Fink for a bug report regarding +;; externally modified files. +;; * Vegard Vesterheim for a bug fix +;; related to `orgtbl-mode'. +;; * Makoto Motohashi for before- and after- +;; export hooks and unit test improvements. +;; * Michael Dwyer for `gfm-mode' underscore regexp. +;; * Chris Lott for suggesting reference label +;; completion. + +;;; 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 . + +;;; 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-18: [Version 2.0][] +;; +;; [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 + + +;;; Code: + +(require 'easymenu) +(require 'outline) +(require 'thingatpt) +(eval-when-compile (require 'cl)) + + +;;; Constants ================================================================= + +(defconst markdown-mode-version "2.0" + "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.") + + +;;; 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-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) + +(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-path "" + "URL of CSS file to link to in the output XHTML." + :group 'markdown + :type 'string) + +(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 block." + :group 'markdown + :type 'string) + +(defcustom markdown-xhtml-standalone-regexp + "^\\(<\\?xml\\|\\).*$" + "Regular expression for matching blockquote lines.") + +(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]]. In this regular +expression, group 1 matches the entire link, including square +brackets, group 2 matches the first component of the wiki link +and group 4 matches the second component, after the pipe, when +present. The meanings of the first and second components depend +on the value of `markdown-wiki-link-alias-first'.") + +(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-block-separator + "\\(\\`\\|\\(\n[ \t]*\n\\)[^\n \t]\\)" + "Regular expression for matching block boundaries.") + +(defconst markdown-regex-math-inline + "\\(^\\|[^\\]\\)\\(\\$\\($\\([^\\$]\\|\\\\.\\)*\\$\\|\\([^\\$]\\|\\\\.\\)*\\)\\$\\)" + "Regular expression for itex $..$ or $$..$$ math mode expressions.") + +(defconst markdown-regex-math-display + "^\\\\\\[\\(.\\|\n\\)*?\\\\\\]$" + "Regular expression for itex \[..\] display mode expressions.") + +(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.") + +(defvar markdown-mode-font-lock-keywords-basic + (list + (cons 'markdown-match-pre-blocks '((0 markdown-pre-face))) + (cons 'markdown-match-fenced-code-blocks '((0 markdown-pre-face))) + (cons markdown-regex-blockquote 'markdown-blockquote-face) + (cons markdown-regex-header-1-setext '((1 markdown-header-face-1) + (2 markdown-header-rule-face))) + (cons markdown-regex-header-2-setext '((1 markdown-header-face-2) + (2 markdown-header-rule-face))) + (cons markdown-regex-header-6-atx '((1 markdown-header-delimiter-face) + (2 markdown-header-face-6) + (3 markdown-header-delimiter-face))) + (cons markdown-regex-header-5-atx '((1 markdown-header-delimiter-face) + (2 markdown-header-face-5) + (3 markdown-header-delimiter-face))) + (cons markdown-regex-header-4-atx '((1 markdown-header-delimiter-face) + (2 markdown-header-face-4) + (3 markdown-header-delimiter-face))) + (cons markdown-regex-header-3-atx '((1 markdown-header-delimiter-face) + (2 markdown-header-face-3) + (3 markdown-header-delimiter-face))) + (cons markdown-regex-header-2-atx '((1 markdown-header-delimiter-face) + (2 markdown-header-face-2) + (3 markdown-header-delimiter-face))) + (cons markdown-regex-header-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-metadata-value-face))) + (cons 'markdown-match-pandoc-metadata '((1 markdown-comment-face) + (2 markdown-metadata-value-face))) + (cons markdown-regex-hr 'markdown-header-face) + (cons 'markdown-match-comments '((0 markdown-comment-face))) + (cons 'markdown-match-code '((0 markdown-inline-code-face))) + (cons markdown-regex-angle-uri 'markdown-link-face) + (cons markdown-regex-uri 'markdown-link-face) + (cons markdown-regex-email 'markdown-link-face) + (cons markdown-regex-list '(2 markdown-list-face)) + (cons markdown-regex-footnote 'markdown-footnote-face) + (cons markdown-regex-link-inline '((1 markdown-link-face t t) + (2 markdown-link-face t) + (4 markdown-url-face t) + (6 markdown-link-title-face t t))) + (cons markdown-regex-link-reference '((1 markdown-link-face t t) + (2 markdown-link-face t) + (4 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-line-break '(1 markdown-line-break-face prepend)) + ) + "Syntax highlighting for Markdown files.") + +(defvar markdown-mode-font-lock-keywords-core + (list + (cons markdown-regex-italic '(2 markdown-italic-face)) + ) + "Additional syntax highlighting for Markdown files. +Includes features which are overridden by some variants.") + +(defconst markdown-mode-font-lock-keywords-math + (list + ;; Math mode $..$ or $$..$$ + (cons markdown-regex-math-inline '(2 markdown-math-face)) + ;; Display mode equations with brackets: \[ \] + (cons markdown-regex-math-display 'markdown-math-face) + ;; Equation reference (eq:foo) + (cons "(eq:[[:alnum:]:_]+)" 'markdown-reference-face) + ;; Equation reference \eqref{foo} + (cons "\\\\eqref{[[:alnum:]:_]+}" 'markdown-reference-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.") + + +;;; 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"))) + + +;;; 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 *$" (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 + (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." + (save-excursion + (forward-line -1) + (markdown-cur-line-indent))) + +(defun markdown-next-line-indent () + "Return the number of leading whitespace characters in the next line." + (save-excursion + (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 + ;; Stop at beginning of buffer + ((bobp) (setq prev nil)) + ;; Continue if 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 prev (point)) + nil) + ;; Stop and return nil at item with lesser indentation + ((< (nth 3 bounds) level) + (setq prev nil) + nil))) + ;; 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-*")) + (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 include the square brackets, like [this]. +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 1))) + (throw 'found + (list (match-string-no-properties 2) + (match-beginning 2) (match-end 2))))))))) + +(defun markdown-get-defined-references () + "Return a list of all defined reference labels (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 1))) + (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'." + (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))))) + + +;;; Markdown Font Lock Matching Functions ===================================== + +(defun markdown-match-comments (last) + "Match HTML comments from the point to LAST." + (cond ((search-forward "") + (make-local-variable 'comment-start-skip) + (setq comment-start-skip "