PageRenderTime 50ms CodeModel.GetById 18ms app.highlight 22ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/markdown-mode.el

http://github.com/rejeep/emacs
Emacs Lisp | 1469 lines | 930 code | 208 blank | 331 comment | 88 complexity | ac1aea4ec1db395bdc9fff72ebcd3168 MD5 | raw file
Possible License(s): GPL-2.0
   1;;; markdown-mode.el --- Major mode to edit Markdown files in Emacs
   2
   3;; Copyright (C) 2007, 2008, 2009 Jason Blevins
   4
   5;; Version: 1.7
   6;; Keywords: Markdown major mode
   7;; Author: Jason Blevins <jrblevin@sdf.lonestar.org>
   8;; URL: http://jblevins.org/projects/markdown-mode/
   9
  10;; This file is not part of GNU Emacs.
  11
  12;; This program is free software; you can redistribute it and/or modify
  13;; it under the terms of the GNU General Public License as published by
  14;; the Free Software Foundation; either version 2, or (at your option)
  15;; any later version.
  16
  17;; This program is distributed in the hope that it will be useful,
  18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20;; GNU General Public License for more details.
  21
  22;; You should have received a copy of the GNU General Public License
  23;; along with this program; if not, write to the Free Software
  24;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25
  26;;; Commentary:
  27
  28;; markdown-mode is a major mode for editing [Markdown][]-formatted
  29;; text files in GNU Emacs.  markdown-mode is free software, licensed
  30;; under the GNU GPL.
  31;;
  32;;  [Markdown]: http://daringfireball.net/projects/markdown/
  33;;
  34;; The latest stable version is markdown-mode 1.7, released on October 1, 2009:
  35;;
  36;;    * [markdown-mode.el][]
  37;;    * [Screenshot][]
  38;;    * [Release notes][]
  39;;
  40;; markdown-mode is also available in the Debian
  41;; [emacs-goodies-el](http://packages.debian.org/emacs-goodies-el)
  42;; package (beginning with revision 27.0-1) and the OpenBSD
  43;; [textproc/markdown-mode](http://pkgsrc.se/textproc/markdown-mode) package.
  44;;
  45;;  [markdown-mode.el]: http://jblevins.org/projects/markdown-mode/markdown-mode.el
  46;;  [screenshot]: http://jblevins.org/projects/markdown-mode/screenshots/20080604-001.png
  47;;  [release notes]: http://jblevins.org/projects/markdown-mode/rev-1-7
  48
  49;; The latest development version can be downloaded directly
  50;; ([markdown-mode.el][devel.el]) or it can be obtained from the
  51;; (browsable and clonable) Git repository at
  52;; <http://jblevins.org/git/markdown-mode.git>.  The entire repository,
  53;; including the full project history, can be cloned via the Git protocol
  54;; by running
  55;;
  56;;     git clone git://jblevins.org/git/markdown-mode.git
  57;;
  58;;  [devel.el]: http://jblevins.org/git/markdown-mode.git/plain/markdown-mode.el
  59
  60;;; Dependencies:
  61
  62;; markdown-mode requires easymenu, a standard package since GNU Emacs
  63;; 19 and XEmacs 19, which provides a uniform interface for creating
  64;; menus in GNU Emacs and XEmacs.
  65
  66;;; Installation:
  67
  68;; Make sure to place `markdown-mode.el` somewhere in the load-path and add
  69;; the following lines to your `.emacs` file to associate markdown-mode
  70;; with `.text` files:
  71;;
  72;;     (autoload 'markdown-mode "markdown-mode.el"
  73;;        "Major mode for editing Markdown files" t)
  74;;     (setq auto-mode-alist
  75;;        (cons '("\\.text" . markdown-mode) auto-mode-alist))
  76;;
  77;; There is no consensus on an official file extension so change `.text` to
  78;; `.mdwn`, `.md`, `.mdt`, or whatever you call your markdown files.
  79
  80;;; Customization:
  81
  82;; Although no configuration is *necessary* there are a few things
  83;; that can be customized.  The `M-x customize-mode` command
  84;; provides an interface to all of the possible customizations:
  85;;
  86;;   * `markdown-command` - the command used to run Markdown
  87;;     (default: `markdown`).
  88;;
  89;;   * `markdown-hr-length` - the length of horizontal rules
  90;;     (default: `5`).
  91;;
  92;;   * `markdown-bold-underscore` - set to a non-nil value to use two
  93;;     underscores for bold instead of two asterisks (default: `nil`).
  94;;
  95;;   * `markdown-italic-underscore` - set to a non-nil value to use
  96;;     underscores for italic instead of asterisks (default: `nil`).
  97;;
  98;;   * `markdown-indent-function` - the function to use for automatic
  99;;     indentation (default: `markdown-indent-line`).
 100;;
 101;;   * `markdown-indent-on-enter` - set to a non-nil value to
 102;;     automatically indent new lines when the enter key is pressed
 103;;     (default: `t`)
 104;;
 105;;   * `markdown-uri-types` - a list of protocols for URIs that
 106;;     `markdown-mode' should highlight.
 107;;
 108;;   * `markdown-enable-math` - syntax highlighting for
 109;;     LaTeX fragments (default: `nil`).
 110;;
 111;; Additionally, the faces used for syntax highlighting can be modified to
 112;; your liking by issuing `M-x customize-group RET markdown-faces`
 113;; or by using the "Markdown Faces" link at the bottom of the mode
 114;; customization screen.
 115
 116;;; Usage:
 117
 118;; Keybindings are grouped by prefixes based on their function.  For
 119;; example, commands dealing with headers begin with `C-c C-t`.  The
 120;; primary commands in each group will are described below.  You can
 121;; obtain a list of all keybindings by pressing `C-c C-h`.
 122;;
 123;;   * Anchors: `C-c C-a`
 124;;
 125;;     `C-c C-a l` inserts inline links of the form `[text](url)`.  If
 126;;     there is an active region, text in the region is used for the
 127;;     link text.  `C-c C-a w` acts similarly for wiki links of the
 128;;     form `[[WikiLink]]`.
 129;;
 130;;   * Commands: `C-c C-c`
 131;;
 132;;     `C-c C-c m` will run Markdown on the current buffer and preview
 133;;     the output in another buffer while `C-c C-c p` runs Markdown on
 134;;     the current buffer and previews the output in a browser.
 135;;
 136;;     `C-c C-c c` will check for undefined references.  If there are
 137;;     any, a small buffer will open with a list of undefined
 138;;     references and the line numbers on which they appear.  In Emacs
 139;;     22 and greater, selecting a reference from this list and
 140;;     pressing `RET` will insert an empty reference definition at the
 141;;     end of the buffer.  Similarly, selecting the line number will
 142;;     jump to the corresponding line.
 143;;
 144;;   * Images: `C-c C-i`
 145;;
 146;;     `C-c C-i i` inserts an image, using the active region (if any)
 147;;     as the alt text.
 148;;
 149;;   * Physical styles: `C-c C-p`
 150;;
 151;;     These commands all act on text in the active region, if any,
 152;;     and insert empty markup fragments otherwise.  `C-c C-p b` makes
 153;;     the selected text bold, `C-c C-p f` formats the region as
 154;;     fixed-width text, and `C-c C-p i` is used for italic text.
 155;;
 156;;   * Logical styles: `C-c C-s`
 157;;
 158;;     These commands all act on text in the active region, if any,
 159;;     and insert empty markup fragments otherwise.  Logical styles
 160;;     include blockquote (`C-c C-s b`), preformatted (`C-c C-s p`),
 161;;     code (`C-c C-s c`), emphasis (`C-c C-s e`), and strong (`C-c
 162;;     C-s s`).
 163;;
 164;;   * Headers: `C-c C-t`
 165;;
 166;;     All header commands use text in the active region, if any, as
 167;;     the header text.  To insert an atx or hash style level-n
 168;;     header, press `C-c C-t n` where n is between 1 and 6.  For a
 169;;     top-level setext or underline style header press `C-c C-t t`
 170;;     (mnemonic: title) and for a second-level underline-style header
 171;;     press `C-c C-t s` (mnemonic: section).
 172;;
 173;;   * Other commands
 174;;
 175;;     `C-c -` inserts a horizontal rule.
 176;;
 177;; Many of the commands described above behave differently depending on
 178;; whether Transient Mark mode is enabled or not.  When it makes sense,
 179;; if Transient Mark mode is on and a region is active, the command
 180;; applies to the text in the region (e.g., `C-c C-p b` makes the region
 181;; bold).  For users who prefer to work outside of Transient Mark mode,
 182;; in Emacs 22 it can be enabled temporarily by pressing `C-SPC C-SPC`.
 183;;
 184;; When applicable, commands that specifically act on the region even
 185;; outside of Transient Mark mode have the same keybinding as the with
 186;; the exception of an additional `C-` prefix.  For example,
 187;; `markdown-insert-blockquote` is bound to `C-c C-s b` and only acts on
 188;; the region in Transient Mark mode while `markdown-blockquote-region`
 189;; is bound to `C-c C-s C-b` and always applies to the region (when
 190;; nonempty).
 191;;
 192;; markdown-mode supports outline-minor-mode as well as org-mode-style
 193;; visibility cycling for atx- or hash-style headers.  There are two
 194;; types of visibility cycling: Pressing `S-TAB` cycles globally between
 195;; the table of contents view (headers only), outline view (top-level
 196;; headers only), and the full document view.  Pressing `TAB` while the
 197;; point is at a header will cycle through levels of visibility for the
 198;; subtree: completely folded, visible children, and fully visible.
 199;; Note that mixing hash and underline style headers will give undesired
 200;; results.
 201
 202;;; Extensions:
 203
 204;; Besides supporting the basic Markdown syntax, markdown-mode also
 205;; includes syntax highlighting for `[[Wiki Links]]` by default.
 206;;
 207;; [SmartyPants][] support is possible by customizing `markdown-command`.
 208;; If you install `SmartyPants.pl` at, say, `/usr/local/bin/smartypants`,
 209;; then you can set `markdown-command` to `"markdown | smartypants"`.
 210;; You can do this either by using `M-x customize-group markdown`
 211;; or by placing the following in your `.emacs` file:
 212;;
 213;;     (defun markdown-custom ()
 214;;       "markdown-mode-hook"
 215;;       (setq markdown-command "markdown | smartypants"))
 216;;     (add-hook 'markdown-mode-hook '(lambda() (markdown-custom)))
 217;;
 218;; [SmartyPants]: http://daringfireball.net/projects/smartypants/
 219;;
 220;; Experimental syntax highlighting for mathematical expressions written
 221;; in LaTeX (only expressions denoted by `$..$`, `$$..$$`, or `\[..\]`)
 222;; can be enabled by setting `markdown-enable-math` to a non-nil value,
 223;; either via customize or by placing `(setq markdown-enable-itex t)`
 224;; in `.emacs`, and restarting Emacs.
 225
 226;;; Acknowledgments:
 227
 228;; markdown-mode has benefited greatly from the efforts of the
 229;; following people:
 230;;
 231;;   * Cyril Brulebois <cyril.brulebois@enst-bretagne.fr> for Debian packaging.
 232;;   * Conal Elliott <conal@conal.net> for a font-lock regexp patch.
 233;;   * Edward O'Connor <hober0@gmail.com> for a font-lock regexp fix.
 234;;   * Greg Bognar <greg_bognar@hms.harvard.edu> for menus and a patch.
 235;;   * Daniel Burrows <dburrows@debian.org> for filing Debian bug #456592.
 236;;   * Peter S. Galbraith <psg@debian.org> for maintaining emacs-goodies-el.
 237;;   * Dmitry Dzhus <mail@sphinx.net.ru> for reference checking functions.
 238;;   * Bryan Kyle <bryan.kyle@gmail.com> for indentation code.
 239;;   * intrigeri <intrigeri@boum.org> for face customizations.
 240;;   * Ankit Solanki <ankit.solanki@gmail.com> for longlines.el compatibility.
 241;;   * Hilko Bengen <bengen@debian.org> for proper XHTML output.
 242;;   * Jose A. Ortega Ruiz <jao@gnu.org> for Emacs 23 fixes.
 243;;   * Alec Resnick <alec@sproutward.org> for bug reports.
 244;;   * Peter Williams <pezra@barelyenough.org> for fill-paragraph enhancements.
 245
 246;;; Bugs:
 247
 248;; Although markdown-mode is developed and tested primarily using
 249;; GNU Emacs 23, compatibility with GNU Emacs 21 and 22 is also a
 250;; priority.
 251;;
 252;; markdown-mode's syntax highlighting is accomplished using the
 253;; search-based fontification features of Emacs through a series of
 254;; regular expressions.  Unfortunately, Emacs has trouble highlighting
 255;; multi-line constructs using regular expressions and this creates
 256;; several syntax-highlighting quirks such as mistaking indented
 257;; lists for preformatted text, etc.  Making markdown-mode's syntax
 258;; highlighting more robust through the use of matching functions
 259;; or syntactic font lock is a high-priority item for future work.
 260;;
 261;; If you find any bugs not mentioned here, please construct a test
 262;; case and/or a patch and email me at <jrblevin@sdf.lonestar.org>.
 263
 264;;; History:
 265
 266;; markdown-mode was written and is maintained by Jason Blevins.  The
 267;; first version was released on May 24, 2007.
 268;;
 269;;   * 2007-05-24: Version 1.1
 270;;   * 2007-05-25: Version 1.2
 271;;   * 2007-06-05: [Version 1.3][]
 272;;   * 2007-06-29: Version 1.4
 273;;   * 2008-05-24: [Version 1.5][]
 274;;   * 2008-06-04: [Version 1.6][]
 275;;   * 2008-10-01: [Version 1.7][]
 276;;
 277;; [Version 1.3]: http://jblevins.org/projects/markdown-mode/rev-1-3
 278;; [Version 1.5]: http://jblevins.org/projects/markdown-mode/rev-1-5
 279;; [Version 1.6]: http://jblevins.org/projects/markdown-mode/rev-1-6
 280;; [Version 1.7]: http://jblevins.org/projects/markdown-mode/rev-1-7
 281
 282
 283
 284
 285;;; Code:
 286
 287(require 'easymenu)
 288(require 'outline)
 289
 290
 291;;; Customizable variables ====================================================
 292
 293;; Current revision
 294(defconst markdown-mode-version "1.7-dev")
 295
 296;; A hook for users to run their own code when the mode is loaded.
 297(defvar markdown-mode-hook nil)
 298
 299
 300;;; Customizable variables ====================================================
 301
 302(defgroup markdown nil
 303  "Major mode for editing text files in Markdown format."
 304  :prefix "markdown-"
 305  :group 'wp
 306  :link '(url-link "http://jblevins.org/projects/markdown-mode/"))
 307
 308(defcustom markdown-command "markdown"
 309  "Command to run markdown."
 310  :group 'markdown
 311  :type 'string)
 312
 313(defcustom markdown-hr-length 5
 314  "Length of horizonal rules."
 315  :group 'markdown
 316  :type 'integer)
 317
 318(defcustom markdown-bold-underscore nil
 319  "Use two underscores for bold instead of two asterisks."
 320  :group 'markdown
 321  :type 'boolean)
 322
 323(defcustom markdown-italic-underscore nil
 324  "Use underscores for italic instead of asterisks."
 325  :group 'markdown
 326  :type 'boolean)
 327
 328(defcustom markdown-indent-function 'markdown-indent-line
 329  "Function to use to indent."
 330  :group 'markdown
 331  :type 'function)
 332
 333(defcustom markdown-indent-on-enter t
 334  "Automatically indent new lines when enter key is pressed."
 335  :group 'markdown
 336  :type 'boolean)
 337
 338(defcustom markdown-uri-types
 339  '("acap" "cid" "data" "dav" "fax" "file" "ftp" "gopher" "http" "https"
 340    "imap" "ldap" "mailto" "mid" "modem" "news" "nfs" "nntp" "pop" "prospero"
 341    "rtsp" "service" "sip" "tel" "telnet" "tip" "urn" "vemmi" "wais")
 342  "Link types for syntax highlighting of URIs."
 343  :group 'markdown
 344  :type 'list)
 345
 346(defcustom markdown-enable-math nil
 347  "Syntax highlighting for inline LaTeX expressions.
 348This will not take effect until Emacs is restarted."
 349  :group 'markdown
 350  :type 'boolean)
 351
 352(defcustom markdown-css-path nil
 353  "CSS file to include in the output XHTML"
 354  :group 'markdown
 355  :type 'string)
 356
 357;;; Font lock =================================================================
 358
 359(require 'font-lock)
 360
 361
 362(defvar markdown-italic-face 'markdown-italic-face
 363  "Face name to use for italic text.")
 364
 365(defvar markdown-bold-face 'markdown-bold-face
 366  "Face name to use for bold text.")
 367
 368(defvar markdown-header-face 'markdown-header-face
 369  "Face name to use as a base for headers.")
 370
 371(defvar markdown-header-face-1 'markdown-header-face-1
 372  "Face name to use for level-1 headers.")
 373
 374(defvar markdown-header-face-2 'markdown-header-face-2
 375  "Face name to use for level-2 headers.")
 376
 377(defvar markdown-header-face-3 'markdown-header-face-3
 378  "Face name to use for level-3 headers.")
 379
 380(defvar markdown-header-face-4 'markdown-header-face-4
 381  "Face name to use for level-4 headers.")
 382
 383(defvar markdown-header-face-5 'markdown-header-face-5
 384  "Face name to use for level-5 headers.")
 385
 386(defvar markdown-header-face-6 'markdown-header-face-6
 387  "Face name to use for level-6 headers.")
 388
 389(defvar markdown-inline-code-face 'markdown-inline-code-face
 390  "Face name to use for inline code.")
 391
 392(defvar markdown-list-face 'markdown-list-face
 393  "Face name to use for list markers.")
 394
 395(defvar markdown-blockquote-face 'markdown-blockquote-face
 396  "Face name to use for blockquote.")
 397
 398(defvar markdown-pre-face 'markdown-pre-face
 399  "Face name to use for preformatted text.")
 400
 401(defvar markdown-link-face 'markdown-link-face
 402  "Face name to use for links.")
 403
 404(defvar markdown-reference-face 'markdown-reference-face
 405  "Face name to use for reference.")
 406
 407(defvar markdown-url-face 'markdown-url-face
 408  "Face name to use for URLs.")
 409
 410(defvar markdown-link-title-face 'markdown-link-title-face
 411  "Face name to use for reference link titles.")
 412
 413(defvar markdown-comment-face 'markdown-comment-face
 414  "Face name to use for HTML comments.")
 415
 416(defvar markdown-math-face 'markdown-math-face
 417  "Face name to use for LaTeX expressions.")
 418
 419
 420(defgroup markdown-faces nil
 421  "Faces used in Markdown Mode"
 422  :group 'markdown
 423  :group 'faces)
 424
 425(defface markdown-italic-face
 426  '((t :inherit font-lock-variable-name-face :italic t))
 427  "Face for italic text."
 428  :group 'markdown-faces)
 429
 430(defface markdown-bold-face
 431  '((t :inherit font-lock-variable-name-face :bold t))
 432  "Face for bold text."
 433  :group 'markdown-faces)
 434
 435(defface markdown-header-face
 436  '((t :inherit font-lock-function-name-face :weight bold))
 437  "Base face for headers."
 438  :group 'markdown-faces)
 439
 440(defface markdown-header-face-1
 441  '((t :inherit markdown-header-face))
 442  "Face for level-1 headers."
 443  :group 'markdown-faces)
 444
 445(defface markdown-header-face-2
 446  '((t :inherit markdown-header-face))
 447  "Face for level-2 headers."
 448  :group 'markdown-faces)
 449
 450(defface markdown-header-face-3
 451  '((t :inherit markdown-header-face))
 452  "Face for level-3 headers."
 453  :group 'markdown-faces)
 454
 455(defface markdown-header-face-4
 456  '((t :inherit markdown-header-face))
 457  "Face for level-4 headers."
 458  :group 'markdown-faces)
 459
 460(defface markdown-header-face-5
 461  '((t :inherit markdown-header-face))
 462  "Face for level-5 headers."
 463  :group 'markdown-faces)
 464
 465(defface markdown-header-face-6
 466  '((t :inherit markdown-header-face))
 467  "Face for level-6 headers."
 468  :group 'markdown-faces)
 469
 470(defface markdown-inline-code-face
 471  '((t :inherit font-lock-constant-face))
 472  "Face for inline code."
 473  :group 'markdown-faces)
 474
 475(defface markdown-list-face
 476  '((t :inherit font-lock-builtin-face))
 477  "Face for list item markers."
 478  :group 'markdown-faces)
 479
 480(defface markdown-blockquote-face
 481  '((t :inherit font-lock-doc-face))
 482  "Face for blockquote sections."
 483  :group 'markdown-faces)
 484
 485(defface markdown-pre-face
 486  '((t :inherit font-lock-constant-face))
 487  "Face for preformatted text."
 488  :group 'markdown-faces)
 489
 490(defface markdown-link-face
 491  '((t :inherit font-lock-keyword-face))
 492  "Face for links."
 493  :group 'markdown-faces)
 494
 495(defface markdown-reference-face
 496  '((t :inherit font-lock-type-face))
 497  "Face for link references."
 498  :group 'markdown-faces)
 499
 500(defface markdown-url-face
 501  '((t :inherit font-lock-string-face))
 502  "Face for URLs."
 503  :group 'markdown-faces)
 504
 505(defface markdown-link-title-face
 506  '((t :inherit font-lock-comment-face))
 507  "Face for reference link titles."
 508  :group 'markdown-faces)
 509
 510(defface markdown-comment-face
 511  '((t :inherit font-lock-comment-face))
 512  "Face for HTML comments."
 513  :group 'markdown-faces)
 514
 515(defface markdown-math-face
 516  '((t :inherit font-lock-string-face))
 517  "Face for LaTeX expressions."
 518  :group 'markdown-faces)
 519
 520(defconst markdown-regex-link-inline
 521  "\\(!?\\[[^]]*?\\]\\)\\(([^\\)]*)\\)"
 522  "Regular expression for a [text](file) or an image link ![text](file).")
 523
 524(defconst markdown-regex-link-reference
 525  "\\(!?\\[[^]]+?\\]\\)[ ]?\\(\\[[^]]*?\\]\\)"
 526  "Regular expression for a reference link [text][id].")
 527
 528(defconst markdown-regex-reference-definition
 529  "^ \\{0,3\\}\\(\\[.+?\\]\\):\\s *\\(.*?\\)\\s *\\( \"[^\"]*\"$\\|$\\)"
 530  "Regular expression for a link definition [id]: ...")
 531
 532(defconst markdown-regex-header-1-atx
 533  "^\\(# \\)\\(.*?\\)\\($\\| #+$\\)"
 534  "Regular expression for level 1 atx-style (hash mark) headers.")
 535
 536(defconst markdown-regex-header-2-atx
 537  "^\\(## \\)\\(.*?\\)\\($\\| #+$\\)"
 538  "Regular expression for level 2 atx-style (hash mark) headers.")
 539
 540(defconst markdown-regex-header-3-atx
 541  "^\\(### \\)\\(.*?\\)\\($\\| #+$\\)"
 542  "Regular expression for level 3 atx-style (hash mark) headers.")
 543
 544(defconst markdown-regex-header-4-atx
 545  "^\\(#### \\)\\(.*?\\)\\($\\| #+$\\)"
 546  "Regular expression for level 4 atx-style (hash mark) headers.")
 547
 548(defconst markdown-regex-header-5-atx
 549  "^\\(##### \\)\\(.*?\\)\\($\\| #+$\\)"
 550  "Regular expression for level 5 atx-style (hash mark) headers.")
 551
 552(defconst markdown-regex-header-6-atx
 553  "^\\(###### \\)\\(.*?\\)\\($\\| #+$\\)"
 554  "Regular expression for level 6 atx-style (hash mark) headers.")
 555
 556(defconst markdown-regex-header-1-setext
 557  "^\\(.*\\)\n\\(===+\\)$"
 558  "Regular expression for level 1 setext-style (underline) headers.")
 559
 560(defconst markdown-regex-header-2-setext
 561  "^\\(.*\\)\n\\(---+\\)$"
 562  "Regular expression for level 2 setext-style (underline) headers.")
 563
 564(defconst markdown-regex-hr
 565  "^\\(\\*[ ]?\\*[ ]?\\*[ ]?[\\* ]*\\|-[ ]?-[ ]?-[--- ]*\\)$"
 566  "Regular expression for matching Markdown horizontal rules.")
 567
 568(defconst markdown-regex-code
 569  "\\(^\\|[^\\]\\)\\(\\(`\\{1,2\\}\\)\\([^ \\]\\|[^ ].*?[^ \\]\\)\\3\\)"
 570  "Regular expression for matching inline code fragments.")
 571
 572(defconst markdown-regex-pre
 573  "^\\(    \\|\t\\).*$"
 574  "Regular expression for matching preformatted text sections.")
 575
 576(defconst markdown-regex-list
 577  "^[ \t]*\\([0-9]+\\.\\|[\\*\\+-]\\) "
 578  "Regular expression for matching list markers.")
 579
 580(defconst markdown-regex-bold
 581  "\\(^\\|[^\\]\\)\\(\\([*_]\\{2\\}\\)\\(.\\|\n\\)*?[^\\ ]\\3\\)"
 582  "Regular expression for matching bold text.")
 583
 584(defconst markdown-regex-italic
 585  "\\(^\\|[^\\]\\)\\(\\([*_]\\)\\([^ \\]\\3\\|[^ ]\\(.\\|\n\\)*?[^\\ ]\\3\\)\\)"
 586  "Regular expression for matching italic text.")
 587
 588(defconst markdown-regex-blockquote
 589  "^>.*$"
 590  "Regular expression for matching blockquote lines.")
 591
 592(defconst markdown-regex-line-break
 593  "  $"
 594  "Regular expression for matching line breaks.")
 595
 596(defconst markdown-regex-wiki-link
 597  "\\[\\[[^]]+\\]\\]"
 598  "Regular expression for matching wiki links.")
 599
 600(defconst markdown-regex-uri
 601  (concat
 602   "\\(" (mapconcat 'identity markdown-uri-types "\\|")
 603   "\\):[^]\t\n\r<>,;() ]+")
 604  "Regular expression for matching inline URIs.")
 605
 606(defconst markdown-regex-angle-uri
 607  (concat
 608   "\\(<\\)\\("
 609   (mapconcat 'identity markdown-uri-types "\\|")
 610   "\\):[^]\t\n\r<>,;()]+\\(>\\)")
 611  "Regular expression for matching inline URIs in angle brackets.")
 612
 613(defconst markdown-regex-email
 614  "<\\(\\sw\\|\\s_\\|\\s.\\)+@\\(\\sw\\|\\s_\\|\\s.\\)+>"
 615  "Regular expression for matching inline email addresses.")
 616
 617(defconst markdown-regex-latex-expression
 618  "\\(^\\|[^\\]\\)\\(\\$\\($\\([^\\$]\\|\\\\.\\)*\\$\\|\\([^\\$]\\|\\\\.\\)*\\)\\$\\)"
 619  "Regular expression for itex $..$ or $$..$$ math mode expressions.")
 620
 621(defconst markdown-regex-latex-display
 622    "^\\\\\\[\\(.\\|\n\\)*?\\\\\\]$"
 623  "Regular expression for itex \[..\] display mode expressions.")
 624
 625(defconst markdown-regex-list-indent
 626  "^\\(\\s *\\)\\([0-9]+\\.\\|[\\*\\+-]\\)\\(\\s +\\)"
 627  "Regular expression for matching indentation of list items.")
 628
 629; From html-helper-mode
 630(defun markdown-match-comments (last)
 631  "Matches HTML comments from the point to LAST"
 632  (cond ((search-forward "<!--" last t)
 633         (backward-char 4)
 634         (let ((beg (point)))
 635           (cond ((search-forward-regexp "--[ \t]*>" last t)
 636                  (set-match-data (list beg (point)))
 637                  t)
 638                 (t nil))))
 639        (t nil)))
 640
 641(defvar markdown-mode-font-lock-keywords-basic
 642  (list
 643   '(markdown-match-comments 0 markdown-comment-face t t)
 644   (cons markdown-regex-code '(2 markdown-inline-code-face))
 645   (cons markdown-regex-pre 'markdown-pre-face)
 646   (cons markdown-regex-blockquote 'markdown-blockquote-face)
 647   (cons markdown-regex-header-1-setext 'markdown-header-face-1)
 648   (cons markdown-regex-header-2-setext 'markdown-header-face-2)
 649   (cons markdown-regex-header-1-atx 'markdown-header-face-1)
 650   (cons markdown-regex-header-2-atx 'markdown-header-face-2)
 651   (cons markdown-regex-header-3-atx 'markdown-header-face-3)
 652   (cons markdown-regex-header-4-atx 'markdown-header-face-4)
 653   (cons markdown-regex-header-5-atx 'markdown-header-face-5)
 654   (cons markdown-regex-header-6-atx 'markdown-header-face-6)
 655   (cons markdown-regex-hr 'markdown-header-face)
 656   (cons markdown-regex-list 'markdown-list-face)
 657   (cons markdown-regex-link-inline
 658         '((1 markdown-link-face t)
 659           (2 markdown-url-face t)))
 660   (cons markdown-regex-link-reference
 661         '((1 markdown-link-face t)
 662           (2 markdown-reference-face t)))
 663   (cons markdown-regex-reference-definition
 664         '((1 markdown-reference-face t)
 665           (2 markdown-url-face t)
 666           (3 markdown-link-title-face t)))
 667   (cons markdown-regex-wiki-link 'markdown-link-face)
 668   (cons markdown-regex-bold '(2 markdown-bold-face))
 669   (cons markdown-regex-italic '(2 markdown-italic-face))
 670   (cons markdown-regex-angle-uri 'markdown-link-face)
 671   (cons markdown-regex-uri 'markdown-link-face)
 672   (cons markdown-regex-email 'markdown-link-face)
 673   )
 674  "Syntax highlighting for Markdown files.")
 675
 676(defconst markdown-mode-font-lock-keywords-latex
 677  (list
 678   ;; Math mode $..$ or $$..$$
 679   (cons markdown-regex-latex-expression '(2 markdown-math-face))
 680   ;; Display mode equations with brackets: \[ \]
 681   (cons markdown-regex-latex-display 'markdown-math-face)
 682   ;; Equation reference (eq:foo)
 683   (cons "(eq:\\w+)" 'markdown-reference-face)
 684   ;; Equation reference \eqref{foo}
 685   (cons "\\\\eqref{\\w+}" 'markdown-reference-face))
 686  "Syntax highlighting for LaTeX fragments.")
 687
 688(defvar markdown-mode-font-lock-keywords
 689  (append
 690   (if markdown-enable-math
 691       markdown-mode-font-lock-keywords-latex)
 692   markdown-mode-font-lock-keywords-basic)
 693  "Default highlighting expressions for Markdown mode.")
 694
 695
 696
 697;;; Syntax Table ==============================================================
 698
 699(defvar markdown-mode-syntax-table
 700  (let ((markdown-mode-syntax-table (make-syntax-table)))
 701    (modify-syntax-entry ?\" "w" markdown-mode-syntax-table)
 702    markdown-mode-syntax-table)
 703  "Syntax table for `markdown-mode'.")
 704
 705
 706
 707;;; Element Insertion =========================================================
 708
 709(defun markdown-wrap-or-insert (s1 s2)
 710 "Insert the strings S1 and S2.
 711If Transient Mark mode is on and a region is active, wrap the strings S1
 712and S2 around the region."
 713 (if (and transient-mark-mode mark-active)
 714     (let ((a (region-beginning)) (b (region-end)))
 715       (goto-char a)
 716       (insert s1)
 717       (goto-char (+ b (length s1)))
 718       (insert s2))
 719   (insert s1 s2)))
 720
 721(defun markdown-insert-hr ()
 722  "Insert a horizonal rule."
 723  (interactive)
 724  (let (hr)
 725    (dotimes (count (- markdown-hr-length 1) hr)        ; Count to n - 1
 726      (setq hr (concat "* " hr)))                       ; Build HR string
 727    (setq hr (concat hr "*\n"))                         ; Add the n-th *
 728    (insert hr)))
 729
 730(defun markdown-insert-bold ()
 731  "Insert markup for a bold word or phrase.
 732If Transient Mark mode is on and a region is active, it is made bold."
 733  (interactive)
 734  (if markdown-bold-underscore
 735      (markdown-wrap-or-insert "__" "__")
 736    (markdown-wrap-or-insert "**" "**"))
 737  (backward-char 2))
 738
 739(defun markdown-insert-italic ()
 740  "Insert markup for an italic word or phrase.
 741If Transient Mark mode is on and a region is active, it is made italic."
 742  (interactive)
 743  (if markdown-italic-underscore
 744      (markdown-wrap-or-insert "_" "_")
 745    (markdown-wrap-or-insert "*" "*"))
 746  (backward-char 1))
 747
 748(defun markdown-insert-code ()
 749  "Insert markup for an inline code fragment.
 750If Transient Mark mode is on and a region is active, it is marked
 751as inline code."
 752  (interactive)
 753  (markdown-wrap-or-insert "`" "`")
 754  (backward-char 1))
 755
 756(defun markdown-insert-link ()
 757  "Insert an inline link of the form []().
 758If Transient Mark mode is on and a region is active, it is used
 759as the link text."
 760  (interactive)
 761  (markdown-wrap-or-insert "[" "]")
 762  (insert "()")
 763  (backward-char 1))
 764
 765(defun markdown-insert-wiki-link ()
 766  "Insert a wiki link of the form [[WikiLink]].
 767If Transient Mark mode is on and a region is active, it is used
 768as the link text."
 769  (interactive)
 770  (markdown-wrap-or-insert "[[" "]]")
 771  (backward-char 2))
 772
 773(defun markdown-insert-image ()
 774  "Insert an inline image tag of the form ![]().
 775If Transient Mark mode is on and a region is active, it is used
 776as the alt text of the image."
 777  (interactive)
 778  (markdown-wrap-or-insert "![" "]")
 779  (insert "()")
 780  (backward-char 1))
 781
 782(defun markdown-insert-header-1 ()
 783  "Insert a first level atx-style (hash mark) header.
 784If Transient Mark mode is on and a region is active, it is used
 785as the header text."
 786  (interactive)
 787  (markdown-insert-header 1))
 788
 789(defun markdown-insert-header-2 ()
 790  "Insert a second level atx-style (hash mark) header.
 791If Transient Mark mode is on and a region is active, it is used
 792as the header text."
 793  (interactive)
 794  (markdown-insert-header 2))
 795
 796(defun markdown-insert-header-3 ()
 797  "Insert a third level atx-style (hash mark) header.
 798If Transient Mark mode is on and a region is active, it is used
 799as the header text."
 800  (interactive)
 801  (markdown-insert-header 3))
 802
 803(defun markdown-insert-header-4 ()
 804  "Insert a fourth level atx-style (hash mark) header.
 805If Transient Mark mode is on and a region is active, it is used
 806as the header text."
 807  (interactive)
 808  (markdown-insert-header 4))
 809
 810(defun markdown-insert-header-5 ()
 811  "Insert a fifth level atx-style (hash mark) header.
 812If Transient Mark mode is on and a region is active, it is used
 813as the header text."
 814  (interactive)
 815  (markdown-insert-header 5))
 816
 817(defun markdown-insert-header-6 ()
 818  "Insert a sixth level atx-style (hash mark) header.
 819If Transient Mark mode is on and a region is active, it is used
 820as the header text."
 821  (interactive)
 822  (markdown-insert-header 6))
 823
 824(defun markdown-insert-header (n)
 825  "Insert an atx-style (hash mark) header.
 826With no prefix argument, insert a level-1 header.  With prefix N,
 827insert a level-N header.  If Transient Mark mode is on and the
 828region is active, it is used as the header text."
 829  (interactive "p")
 830  (unless n                             ; Test to see if n is defined
 831    (setq n 1))                         ; Default to level 1 header
 832  (let (hdr hdrl hdrr)
 833    (dotimes (count n hdr)
 834      (setq hdr (concat "#" hdr)))      ; Build a hash mark header string
 835    (setq hdrl (concat hdr " "))
 836    (setq hdrr (concat " " hdr))
 837    (markdown-wrap-or-insert hdrl hdrr))
 838  (backward-char (+ 1 n)))
 839
 840(defun markdown-insert-title ()
 841  "Insert a setext-style (underline) first level header.
 842If Transient Mark mode is on and a region is active, it is used
 843as the header text."
 844  (interactive)
 845  (if (and transient-mark-mode mark-active)
 846      (let ((a (region-beginning))
 847            (b (region-end))
 848            (len 0)
 849            (hdr))
 850        (setq len (- b a))
 851        (dotimes (count len hdr)
 852          (setq hdr (concat "=" hdr)))  ; Build a === title underline
 853        (end-of-line)
 854        (insert "\n" hdr "\n"))
 855    (insert "\n==========\n")
 856    (backward-char 12)))
 857
 858(defun markdown-insert-section ()
 859  "Insert a setext-style (underline) second level header.
 860If Transient Mark mode is on and a region is active, it is used
 861as the header text."
 862  (interactive)
 863  (if (and transient-mark-mode mark-active)
 864      (let ((a (region-beginning))
 865            (b (region-end))
 866            (len 0)
 867            (hdr))
 868        (setq len (- b a))
 869        (dotimes (count len hdr)
 870          (setq hdr (concat "-" hdr)))  ; Build a --- section underline
 871        (end-of-line)
 872        (insert "\n" hdr "\n"))
 873    (insert "\n----------\n")
 874    (backward-char 12)))
 875
 876(defun markdown-insert-blockquote ()
 877  "Start a blockquote section (or blockquote the region).
 878If Transient Mark mode is on and a region is active, it is used as
 879the blockquote text."
 880  (interactive)
 881  (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
 882      (markdown-blockquote-region (region-beginning) (region-end))
 883    (insert "> ")))
 884
 885(defun markdown-block-region (beg end prefix)
 886  "Format the region using a block prefix.
 887Arguments BEG and END specify the beginning and end of the
 888region.The characters PREFIX will appear at the beginning
 889of each line."
 890  (if mark-active
 891      (save-excursion
 892        (let ((endpos end))
 893          ; Ensure that there is a leading blank line
 894          (goto-char beg)
 895          (while (not (looking-back "\n\n" 2))
 896            (insert "\n")
 897            (setq endpos (+ 1 endpos)))
 898          ; Insert blockquote characters
 899          (move-to-left-margin)
 900          (while (< (point-at-bol) endpos)
 901            (insert prefix)
 902            (setq endpos (+ (length prefix) endpos))
 903            (forward-line))
 904          ; Move back before any blank lines at the end
 905          (goto-char endpos)
 906          (while (looking-back "\n" 1)
 907            (backward-char))
 908          ; Ensure one blank line at the end
 909          (while (not (looking-at "\n\n"))
 910            (insert "\n")
 911            (backward-char))))))
 912
 913(defun markdown-blockquote-region (beg end)
 914  "Blockquote the region.
 915Arguments BEG and END specify the beginning and end of the region."
 916  (interactive "*r")
 917  (markdown-block-region beg end "> "))
 918
 919(defun markdown-insert-pre ()
 920  "Start a preformatted section (or apply to the region).
 921If Transient Mark mode is on and a region is active, it is marked
 922as preformatted text."
 923  (interactive)
 924  (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
 925      (markdown-pre-region (region-beginning) (region-end))
 926    (insert "    ")))
 927
 928(defun markdown-pre-region (beg end)
 929  "Format the region as preformatted text.
 930Arguments BEG and END specify the beginning and end of the region."
 931  (interactive "*r")
 932  (markdown-block-region beg end "    "))
 933
 934;;; Indentation ====================================================================
 935
 936;;; Indentation functions contributed by Bryan Kyle <bryan.kyle@gmail.com>..
 937
 938(defun markdown-indent-find-next-position (cur-pos positions)
 939  "Return the position after the index of CUR-POS in POSITIONS."
 940  (while (and positions
 941              (not (equal cur-pos (car positions))))
 942    (setq positions (cdr positions)))
 943  (or (cadr positions) 0))
 944
 945(defun markdown-prev-line-indent-p ()
 946  "Return t if the previous line is indented."
 947  (save-excursion
 948    (forward-line -1)
 949    (goto-char (point-at-bol))
 950    (if (re-search-forward "^\\s " (point-at-eol) t) t)))
 951
 952(defun markdown-prev-line-indent ()
 953  "Return the number of leading whitespace characters in the previous line."
 954  (save-excursion
 955    (forward-line -1)
 956    (goto-char (point-at-bol))
 957    (when (re-search-forward "^\\s +" (point-at-eol) t)
 958        (current-column))))
 959
 960(defun markdown-prev-list-indent ()
 961  "Return position of the first non-list-marker on the previous line."
 962  (save-excursion
 963    (forward-line -1)
 964    (goto-char (point-at-bol))
 965    (when (re-search-forward markdown-regex-list-indent (point-at-eol) t)
 966        (current-column))))
 967
 968(defun markdown-indent-line ()
 969  "Indent the current line using some heuristics."
 970  (interactive)
 971  (if (markdown-prev-line-indent-p)
 972      ;; If the current column is any of the positions, remove all
 973      ;; of the positions up-to and including the current column
 974      (indent-line-to
 975       (markdown-indent-find-next-position
 976        (current-column) (markdown-calc-indents)))))
 977
 978(defun markdown-calc-indents ()
 979  "Return a list of indentation columns to cycle through."
 980  (let (pos
 981        prev-line-pos
 982        positions
 983        computed-pos)
 984
 985    ;; Previous line indent
 986    (setq prev-line-pos (markdown-prev-line-indent))
 987    (setq positions (cons prev-line-pos positions))
 988
 989    ;; Previous non-list-marker indent
 990    (setq positions (cons (markdown-prev-list-indent) positions))
 991
 992    ;; Indentation of the previous line + tab-width
 993    (cond
 994     (prev-line-pos
 995      (setq positions (cons (+ prev-line-pos tab-width) positions)))
 996     (t
 997      (setq positions (cons tab-width positions))))
 998
 999    ;; Indentation of the previous line - tab-width
1000    (if (and prev-line-pos
1001             (> prev-line-pos tab-width))
1002        (setq positions (cons (- prev-line-pos tab-width) positions)))
1003
1004    ;; Indentation of preceeding list item
1005    (setq pos
1006          (save-excursion
1007            (forward-line -1)
1008            (catch 'break
1009              (while (not (equal (point) (point-min)))
1010                (forward-line -1)
1011                (goto-char (point-at-bol))
1012                (when (re-search-forward markdown-regex-list-indent (point-at-eol) t)
1013                  (throw 'break (length (match-string 1)))))
1014              nil)))
1015    (if pos
1016        (setq positions (cons pos positions)))
1017
1018    ;; First column
1019    (setq positions (cons 0 (reverse positions)))
1020
1021    positions))
1022
1023(defun markdown-enter-key ()
1024  "Insert a newline and optionally indent the next line."
1025  (interactive)
1026  (newline)
1027  (if markdown-indent-on-enter
1028      (funcall indent-line-function)))
1029
1030
1031
1032;;; Keymap ====================================================================
1033
1034(defvar markdown-mode-map
1035  (let ((markdown-mode-map (make-keymap)))
1036    ;; Element insertion
1037    (define-key markdown-mode-map "\C-c\C-al" 'markdown-insert-link)
1038    (define-key markdown-mode-map "\C-c\C-aw" 'markdown-insert-wiki-link)
1039    (define-key markdown-mode-map "\C-c\C-ii" 'markdown-insert-image)
1040    (define-key markdown-mode-map "\C-c\C-t1" 'markdown-insert-header-1)
1041    (define-key markdown-mode-map "\C-c\C-t2" 'markdown-insert-header-2)
1042    (define-key markdown-mode-map "\C-c\C-t3" 'markdown-insert-header-3)
1043    (define-key markdown-mode-map "\C-c\C-t4" 'markdown-insert-header-4)
1044    (define-key markdown-mode-map "\C-c\C-t5" 'markdown-insert-header-5)
1045    (define-key markdown-mode-map "\C-c\C-t6" 'markdown-insert-header-6)
1046    (define-key markdown-mode-map "\C-c\C-pb" 'markdown-insert-bold)
1047    (define-key markdown-mode-map "\C-c\C-ss" 'markdown-insert-bold)
1048    (define-key markdown-mode-map "\C-c\C-pi" 'markdown-insert-italic)
1049    (define-key markdown-mode-map "\C-c\C-se" 'markdown-insert-italic)
1050    (define-key markdown-mode-map "\C-c\C-pf" 'markdown-insert-code)
1051    (define-key markdown-mode-map "\C-c\C-sc" 'markdown-insert-code)
1052    (define-key markdown-mode-map "\C-c\C-sb" 'markdown-insert-blockquote)
1053    (define-key markdown-mode-map "\C-c\C-s\C-b" 'markdown-blockquote-region)
1054    (define-key markdown-mode-map "\C-c\C-sp" 'markdown-insert-pre)
1055    (define-key markdown-mode-map "\C-c\C-s\C-p" 'markdown-pre-region)
1056    (define-key markdown-mode-map "\C-c-" 'markdown-insert-hr)
1057    (define-key markdown-mode-map "\C-c\C-tt" 'markdown-insert-title)
1058    (define-key markdown-mode-map "\C-c\C-ts" 'markdown-insert-section)
1059	;; Indentation
1060	(define-key markdown-mode-map "\C-m" 'markdown-enter-key)
1061    ;; Visibility cycling
1062    (define-key markdown-mode-map (kbd "<tab>") 'markdown-cycle)
1063    (define-key markdown-mode-map (kbd "<S-iso-lefttab>") 'markdown-shifttab)
1064    ;; Markdown functions
1065    (define-key markdown-mode-map "\C-c\C-cm" 'markdown)
1066    (define-key markdown-mode-map "\C-c\C-cp" 'markdown-preview)
1067    ;; References
1068    (define-key markdown-mode-map "\C-c\C-cc" 'markdown-check-refs)
1069    markdown-mode-map)
1070  "Keymap for Markdown major mode.")
1071
1072;;; Menu ==================================================================
1073
1074(easy-menu-define markdown-mode-menu markdown-mode-map
1075  "Menu for Markdown mode"
1076  '("Markdown"
1077    ("Show/Hide"
1078     ["Cycle visibility" markdown-cycle (outline-on-heading-p)]
1079     ["Cycle global visibility" markdown-shifttab])
1080    "---"
1081    ["Compile" markdown]
1082    ["Preview" markdown-preview]
1083    "---"
1084    ("Headers (setext)"
1085     ["Insert Title" markdown-insert-title]
1086     ["Insert Section" markdown-insert-section])
1087    ("Headers (atx)"
1088     ["First level" markdown-insert-header-1]
1089     ["Second level" markdown-insert-header-2]
1090     ["Third level" markdown-insert-header-3]
1091     ["Fourth level" markdown-insert-header-4]
1092     ["Fifth level" markdown-insert-header-5]
1093     ["Sixth level" markdown-insert-header-6])
1094    "---"
1095    ["Bold" markdown-insert-bold]
1096    ["Italic" markdown-insert-italic]
1097    ["Blockquote" markdown-insert-blockquote]
1098    ["Preformatted" markdown-insert-pre]
1099    ["Code" markdown-insert-code]
1100    "---"
1101    ["Insert inline link" markdown-insert-link]
1102    ["Insert image" markdown-insert-image]
1103    ["Insert horizontal rule" markdown-insert-hr]
1104    "---"
1105    ["Check references" markdown-check-refs]
1106    "---"
1107    ["Version" markdown-show-version]
1108    ))
1109
1110
1111
1112;;; References ================================================================
1113
1114;;; Undefined reference checking code by Dmitry Dzhus <mail@sphinx.net.ru>.
1115
1116(defconst markdown-refcheck-buffer
1117  "*Undefined references for %BUFFER%*"
1118  "Pattern for name of buffer for listing undefined references.
1119The string %BUFFER% will be replaced by the corresponding
1120`markdown-mode' buffer name.")
1121
1122(defun markdown-has-reference-definition (reference)
1123    "Find out whether Markdown REFERENCE is defined.
1124
1125REFERENCE should include the square brackets, like [this]."
1126    (let ((reference (downcase reference)))
1127      (save-excursion
1128        (goto-char (point-min))
1129        (catch 'found
1130          (while (re-search-forward markdown-regex-reference-definition nil t)
1131            (when (string= reference (downcase (match-string-no-properties 1)))
1132              (throw 'found t)))))))
1133
1134(defun markdown-get-undefined-refs ()
1135  "Return a list of undefined Markdown references.
1136
1137Result is an alist of pairs (reference . occurencies), where
1138occurencies is itself another alist of pairs (label .
1139line-number).
1140
1141For example, an alist corresponding to [Nice editor][Emacs] at line 12,
1142\[GNU Emacs][Emacs] at line 45 and [manual][elisp] at line 127 is
1143\((\"[emacs]\" (\"[Nice editor]\" . 12) (\"[GNU Emacs]\" . 45)) (\"[elisp]\" (\"[manual]\" . 127)))."
1144  (let ((missing))
1145    (save-excursion
1146      (goto-char (point-min))
1147      (while
1148          (re-search-forward markdown-regex-link-reference nil t)
1149        (let* ((label (match-string-no-properties 1))
1150               (reference (match-string-no-properties 2))
1151               (target (downcase (if (string= reference "[]") label reference))))
1152          (unless (markdown-has-reference-definition target)
1153            (let ((entry (assoc target missing)))
1154              (if (not entry)
1155                  (add-to-list 'missing (cons target
1156                                              (list (cons label (markdown-line-number-at-pos)))) t)
1157                (setcdr entry
1158                        (append (cdr entry) (list (cons label (markdown-line-number-at-pos))))))))))
1159      missing)))
1160
1161(defun markdown-add-missing-ref-definition (ref buffer &optional recheck)
1162  "Add blank REF definition to the end of BUFFER.
1163
1164REF is a Markdown reference in square brackets, like \"[lisp-history]\".
1165
1166When RECHECK is non-nil, BUFFER gets rechecked for undefined
1167references so that REF disappears from the list of those links."
1168  (with-current-buffer buffer
1169      (when (not (eq major-mode 'markdown-mode))
1170        (error "Not available in current mode"))
1171      (goto-char (point-max))
1172      (indent-new-comment-line)
1173      (insert (concat ref ": ")))
1174  (switch-to-buffer-other-window buffer)
1175  (goto-char (point-max))
1176  (when recheck
1177    (markdown-check-refs t)))
1178
1179;; Button which adds an empty Markdown reference definition to the end
1180;; of buffer specified as its 'target-buffer property. Reference name
1181;; is button's label
1182(when (>= emacs-major-version 22)
1183  (define-button-type 'markdown-ref-button
1184    'help-echo "Push to create an empty reference definition"
1185    'face 'bold
1186    'action (lambda (b)
1187              (markdown-add-missing-ref-definition
1188               (button-label b) (button-get b 'target-buffer) t))))
1189
1190;; Button jumping to line in buffer specified as its 'target-buffer
1191;; property. Line number is button's 'line property.
1192(when (>= emacs-major-version 22)
1193  (define-button-type 'goto-line-button
1194    'help-echo "Push to go to this line"
1195    'face 'italic
1196    'action (lambda (b)
1197              (message (button-get b 'buffer))
1198              (switch-to-buffer-other-window (button-get b 'target-buffer))
1199              (goto-line (button-get b 'target-line)))))
1200
1201(defun markdown-check-refs (&optional silent)
1202  "Show all undefined Markdown references in current `markdown-mode' buffer.
1203
1204If SILENT is non-nil, do not message anything when no undefined
1205references found.
1206
1207Links which have empty reference definitions are considered to be
1208defined."
1209  (interactive "P")
1210  (when (not (eq major-mode 'markdown-mode))
1211    (error "Not available in current mode"))
1212  (let ((oldbuf (current-buffer))
1213        (refs (markdown-get-undefined-refs))
1214        (refbuf (get-buffer-create (replace-regexp-in-string
1215                                 "%BUFFER%" (buffer-name)
1216                                 markdown-refcheck-buffer t))))
1217    (if (null refs)
1218        (progn
1219          (when (not silent)
1220            (message "No undefined references found"))
1221          (kill-buffer refbuf))
1222      (with-current-buffer refbuf
1223        (when view-mode
1224          (View-exit-and-edit))
1225        (erase-buffer)
1226        (insert "Following references lack definitions:")
1227        (newline 2)
1228        (dolist (ref refs)
1229          (let ((button-label (format "%s" (car ref))))
1230            (if (>= emacs-major-version 22)
1231                ;; Create a reference button in Emacs 22
1232                (insert-text-button button-label
1233                                    :type 'markdown-ref-button
1234                                    'target-buffer oldbuf)
1235              ;; Insert reference as text in Emacs < 22
1236              (insert button-label)))
1237          (insert " (")
1238          (dolist (occurency (cdr ref))
1239            (let ((line (cdr occurency)))
1240              (if (>= emacs-major-version 22)
1241                  ;; Create a line number button in Emacs 22
1242                  (insert-button (number-to-string line)
1243                                 :type 'goto-line-button
1244                                 'target-buffer oldbuf
1245                                 'target-line line)
1246                ;; Insert line number as text in Emacs < 22
1247                (insert (number-to-string line)))
1248              (insert " "))) (delete-backward-char 1)
1249          (insert ")")
1250          (newline))
1251        (view-buffer-other-window refbuf)
1252        (goto-line 4)))))
1253
1254
1255;;; Outline ===================================================================
1256
1257;; The following visibility cycling code was taken from org-mode
1258;; by Carsten Dominik and adapted for markdown-mode.
1259
1260(defvar markdown-cycle-global-status 1)
1261(defvar markdown-cycle-subtree-status nil)
1262
1263;; Based on org-end-of-subtree from org.el
1264(defun markdown-end-of-subtree (&optional invisible-OK)
1265  "Move to the end of the current subtree.
1266Only visible heading lines are considered, unless INVISIBLE-OK is
1267non-nil."
1268  (outline-back-to-heading invisible-OK)
1269  (let ((first t)
1270        (level (funcall outline-level)))
1271    (while (and (not (eobp))
1272                (or first (> (funcall outline-level) level)))
1273      (setq first nil)
1274      (outline-next-heading))
1275    (if (memq (preceding-char) '(?\n ?\^M))
1276        (progn
1277          ;; Go to end of line before heading
1278          (forward-char -1)
1279          (if (memq (preceding-char) '(?\n ?\^M))
1280              ;; leave blank line before heading
1281              (forward-char -1)))))
1282  (point))
1283
1284;; Based on org-cycle from org.el.
1285(defun markdown-cycle (&optional arg)
1286  "Visibility cycling for Markdown mode.
1287If ARG is t, perform global visibility cycling.  If the point is
1288at an atx-style header, cycle visibility of the corresponding
1289subtree.  Otherwise, insert a tab using `indent-relative'."
1290  (interactive "P")
1291  (cond
1292     ((eq arg t) ;; Global cycling
1293      (cond
1294       ((and (eq last-command this-command)
1295             (eq markdown-cycle-global-status 2))
1296        ;; Move from overview to contents
1297        (hide-sublevels 1)
1298        (message "CONTENTS")
1299        (setq markdown-cycle-global-status 3))
1300
1301       ((and (eq last-command this-command)
1302             (eq markdown-cycle-global-status 3))
1303        ;; Move from contents to all
1304        (show-all)
1305        (message "SHOW ALL")
1306        (setq markdown-cycle-global-status 1))
1307
1308       (t
1309        ;; Defaults to overview
1310        (hide-body)
1311        (message "OVERVIEW")
1312        (setq markdown-cycle-global-status 2))))
1313
1314     ((save-excursion (beginning-of-line 1) (looking-at outline-regexp))
1315      ;; At a heading: rotate between three different views
1316      (outline-back-to-heading)
1317      (let ((goal-column 0) eoh eol eos)
1318        ;; Determine boundaries
1319        (save-excursion
1320          (outline-back-to-heading)
1321          (save-excursion
1322            (beginning-of-line 2)
1323            (while (and (not (eobp)) ;; this is like `next-line'
1324                        (get-char-property (1- (point)) 'invisible))
1325              (beginning-of-line 2)) (setq eol (point)))
1326          (outline-end-of-heading)   (setq eoh (point))
1327          (markdown-end-of-subtree t)
1328          (skip-chars-forward " \t\n")
1329          (beginning-of-line 1) ; in case this is an item
1330          (setq eos (1- (point))))
1331        ;; Find out what to do next and set `this-command'
1332      (cond
1333         ((= eos eoh)
1334          ;; Nothing is hidden behind this heading
1335          (message "EMPTY ENTRY")
1336          (setq markdown-cycle-subtree-status nil))
1337         ((>= eol eos)
1338          ;; Entire subtree is hidden in one line: open it
1339          (show-entry)
1340          (show-children)
1341          (message "CHILDREN")
1342          (setq markdown-cycle-subtree-status 'children))
1343         ((and (eq last-command this-command)
1344               (eq markdown-cycle-subtree-status 'children))
1345          ;; We just showed the children, now show everything.
1346          (show-subtree)
1347          (message "SUBTREE")
1348          (setq markdown-cycle-subtree-status 'subtree))
1349         (t
1350          ;; Default action: hide the subtree.
1351          (hide-subtree)
1352          (message "FOLDED")
1353          (setq markdown-cycle-subtree-status 'folded)))))
1354
1355     (t
1356      (message "TAB")
1357      (funcall indent-line-function))))
1358
1359;; Based on org-shifttab from org.el.
1360(defun markdown-shifttab ()
1361  "Global visibility cycling.
1362Calls `markdown-cycle' with argument t."
1363  (interactive)
1364  (markdown-cycle t))
1365
1366;;; Commands ==================================================================
1367
1368(defun markdown ()
1369  "Run markdown on the current buffer and preview the output in another buffer."
1370  (interactive)
1371  (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
1372      (shell-command-on-region (region-beginning) (region-end) markdown-command
1373                               "*markdown-output*" nil)
1374    (shell-command-on-region (point-min) (point-max) markdown-command
1375                             "*markdown-output*" nil))
1376  (let (title)
1377    (setq title (buffer-name))
1378    (save-excursion
1379      (set-buffer "*markdown-output*")
1380      (goto-char (point-min))
1381      (insert "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
1382              "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
1383              "\t\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n"
1384              "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\n"
1385              "<head>\n<title>")
1386      (insert title)
1387      (insert "</title>\n")
1388      (if markdown-css-path
1389          (insert "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\""
1390                  markdown-css-path
1391                  "\"  />\n"))
1392      (insert "</head>\n\n"
1393              "<body>\n\n")
1394      (goto-char (point-max))
1395      (insert "\n"
1396              "</body>\n"
1397              "</html>\n"))))
1398
1399(defun markdown-preview ()
1400  "Run markdown on the current buffer and preview the output in a browser."
1401  (interactive)
1402  (markdown)
1403  (browse-url-of-buffer "*markdown-output*"))
1404
1405
1406;;; Miscellaneous =============================================================
1407
1408(defun markdown-line-number-at-pos (&optional pos)
1409  "Return (narrowed) buffer line number at position POS.
1410If POS is nil, use current buffer location.
1411This is an exact copy of `line-number-at-pos' for use in emacs21."
1412  (let ((opoint (or pos (point))) start)
1413    (save-excursion
1414      (goto-char (point-min))
1415      (setq start (point))
1416      (goto-char opoint)
1417      (forward-line 0)
1418      (1+ (count-lines start (point))))))
1419
1420(defun markdown-nobreak-p ()
1421  "Returns nil if it is ok for fill-paragraph to insert a line
1422  break at point"
1423  ;; are we inside in square brackets
1424  (looking-back "\\[[^]]*"))
1425
1426
1427
1428;;; Mode definition  ==========================================================
1429
1430(defun markdown-show-version ()
1431  "Show the version number in the minibuffer."
1432  (interactive)
1433  (message "markdown-mode, version %s" markdown-mode-version))
1434
1435(define-derived-mode markdown-mode text-mode "Markdown"
1436  "Major mode for editing Markdown files."
1437  ;; Comments
1438  (make-local-variable 'comment-start)
1439  (setq comment-start "<!-- ")
1440  (make-local-variable 'comment-end)
1441  (setq comment-end " -->")
1442  (make-local-variable 'comment-start-skip)
1443  (setq comment-start-skip "<!--[ \t]*")
1444  (make-local-variable 'comment-column)
1445  (setq comment-column 0)
1446  ;; Font lock.
1447  (set (make-local-variable 'font-lock-defaults)
1448       '(markdown-mode-font-lock-keywords))
1449  (set (make-local-variable 'font-lock-multiline) t)
1450  ;; For menu support in XEmacs
1451  (easy-menu-add markdown-mode-menu markdown-mode-map)
1452  ;; Make filling work with lists (unordered, ordered, and definition)
1453  (set (make-local-variable 'paragraph-start)
1454       "\f\\|[ \t]*$\\|^[ \t]*[*+-] \\|^[ \t*][0-9]+\\.\\|^[ \t]*: ")
1455  ;; Outline mode
1456  (make-local-variable 'outline-regexp)
1457  (setq outline-regexp "#+")
1458  ;; Cause use of ellipses for invisible text.
1459  (add-to-invisibility-spec '(outline . t))
1460  ;; Indentation and filling
1461  (make-local-variable 'fill-nobreak-predicate)
1462  (add-hook 'fill-nobreak-predicate 'markdown-nobreak-p)
1463  (setq indent-line-function markdown-indent-function))
1464
1465;(add-to-list 'auto-mode-alist '("\\.text$" . markdown-mode))
1466
1467(provide 'markdown-mode)
1468
1469;;; markdown-mode.el ends here