;;; 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 "