Thanks
[markdown-mode.git] / markdown-mode.el
blob6559777c2199c92f3937508da08993ff56aec33e
1 ;;; markdown-mode.el --- Major mode to edit Markdown files in Emacs
3 ;; Copyright (C) 2007, 2008, 2009 Jason Blevins
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/
10 ;; This file is not part of GNU Emacs.
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.
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.
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.
26 ;;; Commentary:
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.
32 ;; [Markdown]: http://daringfireball.net/projects/markdown/
34 ;; The latest stable version is markdown-mode 1.7, released on October 1, 2009:
36 ;; * [markdown-mode.el][]
37 ;; * [Screenshot][]
38 ;; * [Release notes][]
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.
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
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
56 ;; git clone git://jblevins.org/git/markdown-mode.git
58 ;; [devel.el]: http://jblevins.org/git/markdown-mode.git/plain/markdown-mode.el
60 ;;; Dependencies:
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.
66 ;;; Installation:
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:
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))
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.
80 ;;; Customization:
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:
86 ;; * `markdown-command` - the command used to run Markdown
87 ;; (default: `markdown`).
89 ;; * `markdown-hr-length` - the length of horizontal rules
90 ;; (default: `5`).
92 ;; * `markdown-bold-underscore` - set to a non-nil value to use two
93 ;; underscores for bold instead of two asterisks (default: `nil`).
95 ;; * `markdown-italic-underscore` - set to a non-nil value to use
96 ;; underscores for italic instead of asterisks (default: `nil`).
98 ;; * `markdown-indent-function` - the function to use for automatic
99 ;; indentation (default: `markdown-indent-line`).
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`)
105 ;; * `markdown-uri-types` - a list of protocols for URIs that
106 ;; `markdown-mode' should highlight.
108 ;; * `markdown-enable-math` - syntax highlighting for
109 ;; LaTeX fragments (default: `nil`).
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.
116 ;;; Usage:
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`.
123 ;; * Anchors: `C-c C-a`
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]]`.
130 ;; * Commands: `C-c C-c`
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.
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.
144 ;; * Images: `C-c C-i`
146 ;; `C-c C-i i` inserts an image, using the active region (if any)
147 ;; as the alt text.
149 ;; * Physical styles: `C-c C-p`
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.
156 ;; * Logical styles: `C-c C-s`
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`).
164 ;; * Headers: `C-c C-t`
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).
173 ;; * Other commands
175 ;; `C-c -` inserts a horizontal rule.
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`.
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).
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.
202 ;;; Extensions:
204 ;; Besides supporting the basic Markdown syntax, markdown-mode also
205 ;; includes syntax highlighting for `[[Wiki Links]]` by default.
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:
213 ;; (defun markdown-custom ()
214 ;; "markdown-mode-hook"
215 ;; (setq markdown-command "markdown | smartypants"))
216 ;; (add-hook 'markdown-mode-hook '(lambda() (markdown-custom)))
218 ;; [SmartyPants]: http://daringfireball.net/projects/smartypants/
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.
226 ;;; Acknowledgments:
228 ;; markdown-mode has benefited greatly from the efforts of the
229 ;; following people:
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 ;; * George Ogata <george.ogata@gmail.com> for fixing several warnings.
247 ;;; Bugs:
249 ;; Although markdown-mode is developed and tested primarily using
250 ;; GNU Emacs 23, compatibility with GNU Emacs 21 and 22 is also a
251 ;; priority.
253 ;; markdown-mode's syntax highlighting is accomplished using the
254 ;; search-based fontification features of Emacs through a series of
255 ;; regular expressions. Unfortunately, Emacs has trouble highlighting
256 ;; multi-line constructs using regular expressions and this creates
257 ;; several syntax-highlighting quirks such as mistaking indented
258 ;; lists for preformatted text, etc. Making markdown-mode's syntax
259 ;; highlighting more robust through the use of matching functions
260 ;; or syntactic font lock is a high-priority item for future work.
262 ;; If you find any bugs not mentioned here, please construct a test
263 ;; case and/or a patch and email me at <jrblevin@sdf.lonestar.org>.
265 ;;; History:
267 ;; markdown-mode was written and is maintained by Jason Blevins. The
268 ;; first version was released on May 24, 2007.
270 ;; * 2007-05-24: Version 1.1
271 ;; * 2007-05-25: Version 1.2
272 ;; * 2007-06-05: [Version 1.3][]
273 ;; * 2007-06-29: Version 1.4
274 ;; * 2008-05-24: [Version 1.5][]
275 ;; * 2008-06-04: [Version 1.6][]
276 ;; * 2008-10-01: [Version 1.7][]
278 ;; [Version 1.3]: http://jblevins.org/projects/markdown-mode/rev-1-3
279 ;; [Version 1.5]: http://jblevins.org/projects/markdown-mode/rev-1-5
280 ;; [Version 1.6]: http://jblevins.org/projects/markdown-mode/rev-1-6
281 ;; [Version 1.7]: http://jblevins.org/projects/markdown-mode/rev-1-7
286 ;;; Code:
288 (require 'easymenu)
289 (require 'outline)
292 ;;; Customizable variables ====================================================
294 ;; Current revision
295 (defconst markdown-mode-version "1.7-dev")
297 ;; A hook for users to run their own code when the mode is loaded.
298 (defvar markdown-mode-hook nil)
301 ;;; Customizable variables ====================================================
303 (defgroup markdown nil
304 "Major mode for editing text files in Markdown format."
305 :prefix "markdown-"
306 :group 'wp
307 :link '(url-link "http://jblevins.org/projects/markdown-mode/"))
309 (defcustom markdown-command "markdown"
310 "Command to run markdown."
311 :group 'markdown
312 :type 'string)
314 (defcustom markdown-hr-length 5
315 "Length of horizonal rules."
316 :group 'markdown
317 :type 'integer)
319 (defcustom markdown-bold-underscore nil
320 "Use two underscores for bold instead of two asterisks."
321 :group 'markdown
322 :type 'boolean)
324 (defcustom markdown-italic-underscore nil
325 "Use underscores for italic instead of asterisks."
326 :group 'markdown
327 :type 'boolean)
329 (defcustom markdown-indent-function 'markdown-indent-line
330 "Function to use to indent."
331 :group 'markdown
332 :type 'function)
334 (defcustom markdown-indent-on-enter t
335 "Automatically indent new lines when enter key is pressed."
336 :group 'markdown
337 :type 'boolean)
339 (defcustom markdown-uri-types
340 '("acap" "cid" "data" "dav" "fax" "file" "ftp" "gopher" "http" "https"
341 "imap" "ldap" "mailto" "mid" "modem" "news" "nfs" "nntp" "pop" "prospero"
342 "rtsp" "service" "sip" "tel" "telnet" "tip" "urn" "vemmi" "wais")
343 "Link types for syntax highlighting of URIs."
344 :group 'markdown
345 :type 'list)
347 (defcustom markdown-enable-math nil
348 "Syntax highlighting for inline LaTeX expressions.
349 This will not take effect until Emacs is restarted."
350 :group 'markdown
351 :type 'boolean)
353 (defcustom markdown-css-path nil
354 "CSS file to include in the output XHTML."
355 :group 'markdown
356 :type 'string)
358 ;;; Font lock =================================================================
360 (require 'font-lock)
363 (defvar markdown-italic-face 'markdown-italic-face
364 "Face name to use for italic text.")
366 (defvar markdown-bold-face 'markdown-bold-face
367 "Face name to use for bold text.")
369 (defvar markdown-header-face 'markdown-header-face
370 "Face name to use as a base for headers.")
372 (defvar markdown-header-face-1 'markdown-header-face-1
373 "Face name to use for level-1 headers.")
375 (defvar markdown-header-face-2 'markdown-header-face-2
376 "Face name to use for level-2 headers.")
378 (defvar markdown-header-face-3 'markdown-header-face-3
379 "Face name to use for level-3 headers.")
381 (defvar markdown-header-face-4 'markdown-header-face-4
382 "Face name to use for level-4 headers.")
384 (defvar markdown-header-face-5 'markdown-header-face-5
385 "Face name to use for level-5 headers.")
387 (defvar markdown-header-face-6 'markdown-header-face-6
388 "Face name to use for level-6 headers.")
390 (defvar markdown-inline-code-face 'markdown-inline-code-face
391 "Face name to use for inline code.")
393 (defvar markdown-list-face 'markdown-list-face
394 "Face name to use for list markers.")
396 (defvar markdown-blockquote-face 'markdown-blockquote-face
397 "Face name to use for blockquote.")
399 (defvar markdown-pre-face 'markdown-pre-face
400 "Face name to use for preformatted text.")
402 (defvar markdown-link-face 'markdown-link-face
403 "Face name to use for links.")
405 (defvar markdown-reference-face 'markdown-reference-face
406 "Face name to use for reference.")
408 (defvar markdown-url-face 'markdown-url-face
409 "Face name to use for URLs.")
411 (defvar markdown-link-title-face 'markdown-link-title-face
412 "Face name to use for reference link titles.")
414 (defvar markdown-comment-face 'markdown-comment-face
415 "Face name to use for HTML comments.")
417 (defvar markdown-math-face 'markdown-math-face
418 "Face name to use for LaTeX expressions.")
421 (defgroup markdown-faces nil
422 "Faces used in Markdown Mode"
423 :group 'markdown
424 :group 'faces)
426 (defface markdown-italic-face
427 '((t :inherit font-lock-variable-name-face :italic t))
428 "Face for italic text."
429 :group 'markdown-faces)
431 (defface markdown-bold-face
432 '((t :inherit font-lock-variable-name-face :bold t))
433 "Face for bold text."
434 :group 'markdown-faces)
436 (defface markdown-header-face
437 '((t :inherit font-lock-function-name-face :weight bold))
438 "Base face for headers."
439 :group 'markdown-faces)
441 (defface markdown-header-face-1
442 '((t :inherit markdown-header-face))
443 "Face for level-1 headers."
444 :group 'markdown-faces)
446 (defface markdown-header-face-2
447 '((t :inherit markdown-header-face))
448 "Face for level-2 headers."
449 :group 'markdown-faces)
451 (defface markdown-header-face-3
452 '((t :inherit markdown-header-face))
453 "Face for level-3 headers."
454 :group 'markdown-faces)
456 (defface markdown-header-face-4
457 '((t :inherit markdown-header-face))
458 "Face for level-4 headers."
459 :group 'markdown-faces)
461 (defface markdown-header-face-5
462 '((t :inherit markdown-header-face))
463 "Face for level-5 headers."
464 :group 'markdown-faces)
466 (defface markdown-header-face-6
467 '((t :inherit markdown-header-face))
468 "Face for level-6 headers."
469 :group 'markdown-faces)
471 (defface markdown-inline-code-face
472 '((t :inherit font-lock-constant-face))
473 "Face for inline code."
474 :group 'markdown-faces)
476 (defface markdown-list-face
477 '((t :inherit font-lock-builtin-face))
478 "Face for list item markers."
479 :group 'markdown-faces)
481 (defface markdown-blockquote-face
482 '((t :inherit font-lock-doc-face))
483 "Face for blockquote sections."
484 :group 'markdown-faces)
486 (defface markdown-pre-face
487 '((t :inherit font-lock-constant-face))
488 "Face for preformatted text."
489 :group 'markdown-faces)
491 (defface markdown-link-face
492 '((t :inherit font-lock-keyword-face))
493 "Face for links."
494 :group 'markdown-faces)
496 (defface markdown-reference-face
497 '((t :inherit font-lock-type-face))
498 "Face for link references."
499 :group 'markdown-faces)
501 (defface markdown-url-face
502 '((t :inherit font-lock-string-face))
503 "Face for URLs."
504 :group 'markdown-faces)
506 (defface markdown-link-title-face
507 '((t :inherit font-lock-comment-face))
508 "Face for reference link titles."
509 :group 'markdown-faces)
511 (defface markdown-comment-face
512 '((t :inherit font-lock-comment-face))
513 "Face for HTML comments."
514 :group 'markdown-faces)
516 (defface markdown-math-face
517 '((t :inherit font-lock-string-face))
518 "Face for LaTeX expressions."
519 :group 'markdown-faces)
521 (defconst markdown-regex-link-inline
522 "\\(!?\\[[^]]*?\\]\\)\\(([^\\)]*)\\)"
523 "Regular expression for a [text](file) or an image link ![text](file).")
525 (defconst markdown-regex-link-reference
526 "\\(!?\\[[^]]+?\\]\\)[ ]?\\(\\[[^]]*?\\]\\)"
527 "Regular expression for a reference link [text][id].")
529 (defconst markdown-regex-reference-definition
530 "^ \\{0,3\\}\\(\\[.+?\\]\\):\\s *\\(.*?\\)\\s *\\( \"[^\"]*\"$\\|$\\)"
531 "Regular expression for a link definition [id]: ...")
533 (defconst markdown-regex-header-1-atx
534 "^\\(# \\)\\(.*?\\)\\($\\| #+$\\)"
535 "Regular expression for level 1 atx-style (hash mark) headers.")
537 (defconst markdown-regex-header-2-atx
538 "^\\(## \\)\\(.*?\\)\\($\\| #+$\\)"
539 "Regular expression for level 2 atx-style (hash mark) headers.")
541 (defconst markdown-regex-header-3-atx
542 "^\\(### \\)\\(.*?\\)\\($\\| #+$\\)"
543 "Regular expression for level 3 atx-style (hash mark) headers.")
545 (defconst markdown-regex-header-4-atx
546 "^\\(#### \\)\\(.*?\\)\\($\\| #+$\\)"
547 "Regular expression for level 4 atx-style (hash mark) headers.")
549 (defconst markdown-regex-header-5-atx
550 "^\\(##### \\)\\(.*?\\)\\($\\| #+$\\)"
551 "Regular expression for level 5 atx-style (hash mark) headers.")
553 (defconst markdown-regex-header-6-atx
554 "^\\(###### \\)\\(.*?\\)\\($\\| #+$\\)"
555 "Regular expression for level 6 atx-style (hash mark) headers.")
557 (defconst markdown-regex-header-1-setext
558 "^\\(.*\\)\n\\(===+\\)$"
559 "Regular expression for level 1 setext-style (underline) headers.")
561 (defconst markdown-regex-header-2-setext
562 "^\\(.*\\)\n\\(---+\\)$"
563 "Regular expression for level 2 setext-style (underline) headers.")
565 (defconst markdown-regex-hr
566 "^\\(\\*[ ]?\\*[ ]?\\*[ ]?[\\* ]*\\|-[ ]?-[ ]?-[--- ]*\\)$"
567 "Regular expression for matching Markdown horizontal rules.")
569 (defconst markdown-regex-code
570 "\\(^\\|[^\\]\\)\\(\\(`\\{1,2\\}\\)\\([^ \\]\\|[^ ].*?[^ \\]\\)\\3\\)"
571 "Regular expression for matching inline code fragments.")
573 (defconst markdown-regex-pre
574 "^\\( \\|\t\\).*$"
575 "Regular expression for matching preformatted text sections.")
577 (defconst markdown-regex-list
578 "^[ \t]*\\([0-9]+\\.\\|[\\*\\+-]\\) "
579 "Regular expression for matching list markers.")
581 (defconst markdown-regex-bold
582 "\\(^\\|[^\\]\\)\\(\\([*_]\\{2\\}\\)\\(.\\|\n\\)*?[^\\ ]\\3\\)"
583 "Regular expression for matching bold text.")
585 (defconst markdown-regex-italic
586 "\\(^\\|[^\\]\\)\\(\\([*_]\\)\\([^ \\]\\3\\|[^ ]\\(.\\|\n\\)*?[^\\ ]\\3\\)\\)"
587 "Regular expression for matching italic text.")
589 (defconst markdown-regex-blockquote
590 "^>.*$"
591 "Regular expression for matching blockquote lines.")
593 (defconst markdown-regex-line-break
594 " $"
595 "Regular expression for matching line breaks.")
597 (defconst markdown-regex-wiki-link
598 "\\[\\[[^]]+\\]\\]"
599 "Regular expression for matching wiki links.")
601 (defconst markdown-regex-uri
602 (concat
603 "\\(" (mapconcat 'identity markdown-uri-types "\\|")
604 "\\):[^]\t\n\r<>,;() ]+")
605 "Regular expression for matching inline URIs.")
607 (defconst markdown-regex-angle-uri
608 (concat
609 "\\(<\\)\\("
610 (mapconcat 'identity markdown-uri-types "\\|")
611 "\\):[^]\t\n\r<>,;()]+\\(>\\)")
612 "Regular expression for matching inline URIs in angle brackets.")
614 (defconst markdown-regex-email
615 "<\\(\\sw\\|\\s_\\|\\s.\\)+@\\(\\sw\\|\\s_\\|\\s.\\)+>"
616 "Regular expression for matching inline email addresses.")
618 (defconst markdown-regex-latex-expression
619 "\\(^\\|[^\\]\\)\\(\\$\\($\\([^\\$]\\|\\\\.\\)*\\$\\|\\([^\\$]\\|\\\\.\\)*\\)\\$\\)"
620 "Regular expression for itex $..$ or $$..$$ math mode expressions.")
622 (defconst markdown-regex-latex-display
623 "^\\\\\\[\\(.\\|\n\\)*?\\\\\\]$"
624 "Regular expression for itex \[..\] display mode expressions.")
626 (defconst markdown-regex-list-indent
627 "^\\(\\s *\\)\\([0-9]+\\.\\|[\\*\\+-]\\)\\(\\s +\\)"
628 "Regular expression for matching indentation of list items.")
630 ; From html-helper-mode
631 (defun markdown-match-comments (last)
632 "Match HTML comments from the point to LAST."
633 (cond ((search-forward "<!--" last t)
634 (backward-char 4)
635 (let ((beg (point)))
636 (cond ((search-forward-regexp "--[ \t]*>" last t)
637 (set-match-data (list beg (point)))
639 (t nil))))
640 (t nil)))
642 (defvar markdown-mode-font-lock-keywords-basic
643 (list
644 '(markdown-match-comments 0 markdown-comment-face t t)
645 (cons markdown-regex-code '(2 markdown-inline-code-face))
646 (cons markdown-regex-pre 'markdown-pre-face)
647 (cons markdown-regex-blockquote 'markdown-blockquote-face)
648 (cons markdown-regex-header-1-setext 'markdown-header-face-1)
649 (cons markdown-regex-header-2-setext 'markdown-header-face-2)
650 (cons markdown-regex-header-1-atx 'markdown-header-face-1)
651 (cons markdown-regex-header-2-atx 'markdown-header-face-2)
652 (cons markdown-regex-header-3-atx 'markdown-header-face-3)
653 (cons markdown-regex-header-4-atx 'markdown-header-face-4)
654 (cons markdown-regex-header-5-atx 'markdown-header-face-5)
655 (cons markdown-regex-header-6-atx 'markdown-header-face-6)
656 (cons markdown-regex-hr 'markdown-header-face)
657 (cons markdown-regex-list 'markdown-list-face)
658 (cons markdown-regex-link-inline
659 '((1 markdown-link-face t)
660 (2 markdown-url-face t)))
661 (cons markdown-regex-link-reference
662 '((1 markdown-link-face t)
663 (2 markdown-reference-face t)))
664 (cons markdown-regex-reference-definition
665 '((1 markdown-reference-face t)
666 (2 markdown-url-face t)
667 (3 markdown-link-title-face t)))
668 (cons markdown-regex-wiki-link 'markdown-link-face)
669 (cons markdown-regex-bold '(2 markdown-bold-face))
670 (cons markdown-regex-italic '(2 markdown-italic-face))
671 (cons markdown-regex-angle-uri 'markdown-link-face)
672 (cons markdown-regex-uri 'markdown-link-face)
673 (cons markdown-regex-email 'markdown-link-face)
675 "Syntax highlighting for Markdown files.")
677 (defconst markdown-mode-font-lock-keywords-latex
678 (list
679 ;; Math mode $..$ or $$..$$
680 (cons markdown-regex-latex-expression '(2 markdown-math-face))
681 ;; Display mode equations with brackets: \[ \]
682 (cons markdown-regex-latex-display 'markdown-math-face)
683 ;; Equation reference (eq:foo)
684 (cons "(eq:\\w+)" 'markdown-reference-face)
685 ;; Equation reference \eqref{foo}
686 (cons "\\\\eqref{\\w+}" 'markdown-reference-face))
687 "Syntax highlighting for LaTeX fragments.")
689 (defvar markdown-mode-font-lock-keywords
690 (append
691 (if markdown-enable-math
692 markdown-mode-font-lock-keywords-latex)
693 markdown-mode-font-lock-keywords-basic)
694 "Default highlighting expressions for Markdown mode.")
698 ;;; Syntax Table ==============================================================
700 (defvar markdown-mode-syntax-table
701 (let ((markdown-mode-syntax-table (make-syntax-table)))
702 (modify-syntax-entry ?\" "w" markdown-mode-syntax-table)
703 markdown-mode-syntax-table)
704 "Syntax table for `markdown-mode'.")
708 ;;; Element Insertion =========================================================
710 (defun markdown-wrap-or-insert (s1 s2)
711 "Insert the strings S1 and S2.
712 If Transient Mark mode is on and a region is active, wrap the strings S1
713 and S2 around the region."
714 (if (and transient-mark-mode mark-active)
715 (let ((a (region-beginning)) (b (region-end)))
716 (goto-char a)
717 (insert s1)
718 (goto-char (+ b (length s1)))
719 (insert s2))
720 (insert s1 s2)))
722 (defun markdown-insert-hr ()
723 "Insert a horizonal rule."
724 (interactive)
725 (let (hr)
726 (dotimes (count (- markdown-hr-length 1) hr) ; Count to n - 1
727 (setq hr (concat "* " hr))) ; Build HR string
728 (setq hr (concat hr "*\n")) ; Add the n-th *
729 (insert hr)))
731 (defun markdown-insert-bold ()
732 "Insert markup for a bold word or phrase.
733 If Transient Mark mode is on and a region is active, it is made bold."
734 (interactive)
735 (if markdown-bold-underscore
736 (markdown-wrap-or-insert "__" "__")
737 (markdown-wrap-or-insert "**" "**"))
738 (backward-char 2))
740 (defun markdown-insert-italic ()
741 "Insert markup for an italic word or phrase.
742 If Transient Mark mode is on and a region is active, it is made italic."
743 (interactive)
744 (if markdown-italic-underscore
745 (markdown-wrap-or-insert "_" "_")
746 (markdown-wrap-or-insert "*" "*"))
747 (backward-char 1))
749 (defun markdown-insert-code ()
750 "Insert markup for an inline code fragment.
751 If Transient Mark mode is on and a region is active, it is marked
752 as inline code."
753 (interactive)
754 (markdown-wrap-or-insert "`" "`")
755 (backward-char 1))
757 (defun markdown-insert-link ()
758 "Insert an inline link of the form []().
759 If Transient Mark mode is on and a region is active, it is used
760 as the link text."
761 (interactive)
762 (markdown-wrap-or-insert "[" "]")
763 (insert "()")
764 (backward-char 1))
766 (defun markdown-insert-wiki-link ()
767 "Insert a wiki link of the form [[WikiLink]].
768 If Transient Mark mode is on and a region is active, it is used
769 as the link text."
770 (interactive)
771 (markdown-wrap-or-insert "[[" "]]")
772 (backward-char 2))
774 (defun markdown-insert-image ()
775 "Insert an inline image tag of the form ![]().
776 If Transient Mark mode is on and a region is active, it is used
777 as the alt text of the image."
778 (interactive)
779 (markdown-wrap-or-insert "![" "]")
780 (insert "()")
781 (backward-char 1))
783 (defun markdown-insert-header-1 ()
784 "Insert a first level atx-style (hash mark) header.
785 If Transient Mark mode is on and a region is active, it is used
786 as the header text."
787 (interactive)
788 (markdown-insert-header 1))
790 (defun markdown-insert-header-2 ()
791 "Insert a second level atx-style (hash mark) header.
792 If Transient Mark mode is on and a region is active, it is used
793 as the header text."
794 (interactive)
795 (markdown-insert-header 2))
797 (defun markdown-insert-header-3 ()
798 "Insert a third level atx-style (hash mark) header.
799 If Transient Mark mode is on and a region is active, it is used
800 as the header text."
801 (interactive)
802 (markdown-insert-header 3))
804 (defun markdown-insert-header-4 ()
805 "Insert a fourth level atx-style (hash mark) header.
806 If Transient Mark mode is on and a region is active, it is used
807 as the header text."
808 (interactive)
809 (markdown-insert-header 4))
811 (defun markdown-insert-header-5 ()
812 "Insert a fifth level atx-style (hash mark) header.
813 If Transient Mark mode is on and a region is active, it is used
814 as the header text."
815 (interactive)
816 (markdown-insert-header 5))
818 (defun markdown-insert-header-6 ()
819 "Insert a sixth level atx-style (hash mark) header.
820 If Transient Mark mode is on and a region is active, it is used
821 as the header text."
822 (interactive)
823 (markdown-insert-header 6))
825 (defun markdown-insert-header (n)
826 "Insert an atx-style (hash mark) header.
827 With no prefix argument, insert a level-1 header. With prefix N,
828 insert a level-N header. If Transient Mark mode is on and the
829 region is active, it is used as the header text."
830 (interactive "p")
831 (unless n ; Test to see if n is defined
832 (setq n 1)) ; Default to level 1 header
833 (let (hdr hdrl hdrr)
834 (dotimes (count n hdr)
835 (setq hdr (concat "#" hdr))) ; Build a hash mark header string
836 (setq hdrl (concat hdr " "))
837 (setq hdrr (concat " " hdr))
838 (markdown-wrap-or-insert hdrl hdrr))
839 (backward-char (+ 1 n)))
841 (defun markdown-insert-title ()
842 "Insert a setext-style (underline) first level header.
843 If Transient Mark mode is on and a region is active, it is used
844 as the header text."
845 (interactive)
846 (if (and transient-mark-mode mark-active)
847 (let ((a (region-beginning))
848 (b (region-end))
849 (len 0)
850 (hdr))
851 (setq len (- b a))
852 (dotimes (count len hdr)
853 (setq hdr (concat "=" hdr))) ; Build a === title underline
854 (end-of-line)
855 (insert "\n" hdr "\n"))
856 (insert "\n==========\n")
857 (backward-char 12)))
859 (defun markdown-insert-section ()
860 "Insert a setext-style (underline) second level header.
861 If Transient Mark mode is on and a region is active, it is used
862 as the header text."
863 (interactive)
864 (if (and transient-mark-mode mark-active)
865 (let ((a (region-beginning))
866 (b (region-end))
867 (len 0)
868 (hdr))
869 (setq len (- b a))
870 (dotimes (count len hdr)
871 (setq hdr (concat "-" hdr))) ; Build a --- section underline
872 (end-of-line)
873 (insert "\n" hdr "\n"))
874 (insert "\n----------\n")
875 (backward-char 12)))
877 (defun markdown-insert-blockquote ()
878 "Start a blockquote section (or blockquote the region).
879 If Transient Mark mode is on and a region is active, it is used as
880 the blockquote text."
881 (interactive)
882 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
883 (markdown-blockquote-region (region-beginning) (region-end))
884 (insert "> ")))
886 (defun markdown-block-region (beg end prefix)
887 "Format the region using a block prefix.
888 Arguments BEG and END specify the beginning and end of the
889 region.The characters PREFIX will appear at the beginning
890 of each line."
891 (if mark-active
892 (save-excursion
893 (let ((endpos end))
894 ; Ensure that there is a leading blank line
895 (goto-char beg)
896 (while (not (looking-back "\n\n" 2))
897 (insert "\n")
898 (setq endpos (+ 1 endpos)))
899 ; Insert blockquote characters
900 (move-to-left-margin)
901 (while (< (point-at-bol) endpos)
902 (insert prefix)
903 (setq endpos (+ (length prefix) endpos))
904 (forward-line))
905 ; Move back before any blank lines at the end
906 (goto-char endpos)
907 (while (looking-back "\n" 1)
908 (backward-char))
909 ; Ensure one blank line at the end
910 (while (not (looking-at "\n\n"))
911 (insert "\n")
912 (backward-char))))))
914 (defun markdown-blockquote-region (beg end)
915 "Blockquote the region.
916 Arguments BEG and END specify the beginning and end of the region."
917 (interactive "*r")
918 (markdown-block-region beg end "> "))
920 (defun markdown-insert-pre ()
921 "Start a preformatted section (or apply to the region).
922 If Transient Mark mode is on and a region is active, it is marked
923 as preformatted text."
924 (interactive)
925 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
926 (markdown-pre-region (region-beginning) (region-end))
927 (insert " ")))
929 (defun markdown-pre-region (beg end)
930 "Format the region as preformatted text.
931 Arguments BEG and END specify the beginning and end of the region."
932 (interactive "*r")
933 (markdown-block-region beg end " "))
935 ;;; Indentation ====================================================================
937 ;;; Indentation functions contributed by Bryan Kyle <bryan.kyle@gmail.com>..
939 (defun markdown-indent-find-next-position (cur-pos positions)
940 "Return the position after the index of CUR-POS in POSITIONS."
941 (while (and positions
942 (not (equal cur-pos (car positions))))
943 (setq positions (cdr positions)))
944 (or (cadr positions) 0))
946 (defun markdown-prev-line-indent-p ()
947 "Return t if the previous line is indented."
948 (save-excursion
949 (forward-line -1)
950 (goto-char (point-at-bol))
951 (if (re-search-forward "^\\s " (point-at-eol) t) t)))
953 (defun markdown-prev-line-indent ()
954 "Return the number of leading whitespace characters in the previous line."
955 (save-excursion
956 (forward-line -1)
957 (goto-char (point-at-bol))
958 (when (re-search-forward "^\\s +" (point-at-eol) t)
959 (current-column))))
961 (defun markdown-prev-list-indent ()
962 "Return position of the first non-list-marker on the previous line."
963 (save-excursion
964 (forward-line -1)
965 (goto-char (point-at-bol))
966 (when (re-search-forward markdown-regex-list-indent (point-at-eol) t)
967 (current-column))))
969 (defun markdown-indent-line ()
970 "Indent the current line using some heuristics."
971 (interactive)
972 (if (markdown-prev-line-indent-p)
973 ;; If the current column is any of the positions, remove all
974 ;; of the positions up-to and including the current column
975 (indent-line-to
976 (markdown-indent-find-next-position
977 (current-column) (markdown-calc-indents)))))
979 (defun markdown-calc-indents ()
980 "Return a list of indentation columns to cycle through."
981 (let (pos
982 prev-line-pos
983 positions
984 computed-pos)
986 ;; Previous line indent
987 (setq prev-line-pos (markdown-prev-line-indent))
988 (setq positions (cons prev-line-pos positions))
990 ;; Previous non-list-marker indent
991 (setq positions (cons (markdown-prev-list-indent) positions))
993 ;; Indentation of the previous line + tab-width
994 (cond
995 (prev-line-pos
996 (setq positions (cons (+ prev-line-pos tab-width) positions)))
998 (setq positions (cons tab-width positions))))
1000 ;; Indentation of the previous line - tab-width
1001 (if (and prev-line-pos
1002 (> prev-line-pos tab-width))
1003 (setq positions (cons (- prev-line-pos tab-width) positions)))
1005 ;; Indentation of preceeding list item
1006 (setq pos
1007 (save-excursion
1008 (forward-line -1)
1009 (catch 'break
1010 (while (not (equal (point) (point-min)))
1011 (forward-line -1)
1012 (goto-char (point-at-bol))
1013 (when (re-search-forward markdown-regex-list-indent (point-at-eol) t)
1014 (throw 'break (length (match-string 1)))))
1015 nil)))
1016 (if pos
1017 (setq positions (cons pos positions)))
1019 ;; First column
1020 (setq positions (cons 0 (reverse positions)))
1022 positions))
1024 (defun markdown-enter-key ()
1025 "Insert a newline and optionally indent the next line."
1026 (interactive)
1027 (newline)
1028 (if markdown-indent-on-enter
1029 (funcall indent-line-function)))
1033 ;;; Keymap ====================================================================
1035 (defvar markdown-mode-map
1036 (let ((markdown-mode-map (make-keymap)))
1037 ;; Element insertion
1038 (define-key markdown-mode-map "\C-c\C-al" 'markdown-insert-link)
1039 (define-key markdown-mode-map "\C-c\C-aw" 'markdown-insert-wiki-link)
1040 (define-key markdown-mode-map "\C-c\C-ii" 'markdown-insert-image)
1041 (define-key markdown-mode-map "\C-c\C-t1" 'markdown-insert-header-1)
1042 (define-key markdown-mode-map "\C-c\C-t2" 'markdown-insert-header-2)
1043 (define-key markdown-mode-map "\C-c\C-t3" 'markdown-insert-header-3)
1044 (define-key markdown-mode-map "\C-c\C-t4" 'markdown-insert-header-4)
1045 (define-key markdown-mode-map "\C-c\C-t5" 'markdown-insert-header-5)
1046 (define-key markdown-mode-map "\C-c\C-t6" 'markdown-insert-header-6)
1047 (define-key markdown-mode-map "\C-c\C-pb" 'markdown-insert-bold)
1048 (define-key markdown-mode-map "\C-c\C-ss" 'markdown-insert-bold)
1049 (define-key markdown-mode-map "\C-c\C-pi" 'markdown-insert-italic)
1050 (define-key markdown-mode-map "\C-c\C-se" 'markdown-insert-italic)
1051 (define-key markdown-mode-map "\C-c\C-pf" 'markdown-insert-code)
1052 (define-key markdown-mode-map "\C-c\C-sc" 'markdown-insert-code)
1053 (define-key markdown-mode-map "\C-c\C-sb" 'markdown-insert-blockquote)
1054 (define-key markdown-mode-map "\C-c\C-s\C-b" 'markdown-blockquote-region)
1055 (define-key markdown-mode-map "\C-c\C-sp" 'markdown-insert-pre)
1056 (define-key markdown-mode-map "\C-c\C-s\C-p" 'markdown-pre-region)
1057 (define-key markdown-mode-map "\C-c-" 'markdown-insert-hr)
1058 (define-key markdown-mode-map "\C-c\C-tt" 'markdown-insert-title)
1059 (define-key markdown-mode-map "\C-c\C-ts" 'markdown-insert-section)
1060 ;; Indentation
1061 (define-key markdown-mode-map "\C-m" 'markdown-enter-key)
1062 ;; Visibility cycling
1063 (define-key markdown-mode-map (kbd "<tab>") 'markdown-cycle)
1064 (define-key markdown-mode-map (kbd "<S-iso-lefttab>") 'markdown-shifttab)
1065 ;; Markdown functions
1066 (define-key markdown-mode-map "\C-c\C-cm" 'markdown)
1067 (define-key markdown-mode-map "\C-c\C-cp" 'markdown-preview)
1068 ;; References
1069 (define-key markdown-mode-map "\C-c\C-cc" 'markdown-check-refs)
1070 markdown-mode-map)
1071 "Keymap for Markdown major mode.")
1073 ;;; Menu ==================================================================
1075 (easy-menu-define markdown-mode-menu markdown-mode-map
1076 "Menu for Markdown mode"
1077 '("Markdown"
1078 ("Show/Hide"
1079 ["Cycle visibility" markdown-cycle (outline-on-heading-p)]
1080 ["Cycle global visibility" markdown-shifttab])
1081 "---"
1082 ["Compile" markdown]
1083 ["Preview" markdown-preview]
1084 "---"
1085 ("Headers (setext)"
1086 ["Insert Title" markdown-insert-title]
1087 ["Insert Section" markdown-insert-section])
1088 ("Headers (atx)"
1089 ["First level" markdown-insert-header-1]
1090 ["Second level" markdown-insert-header-2]
1091 ["Third level" markdown-insert-header-3]
1092 ["Fourth level" markdown-insert-header-4]
1093 ["Fifth level" markdown-insert-header-5]
1094 ["Sixth level" markdown-insert-header-6])
1095 "---"
1096 ["Bold" markdown-insert-bold]
1097 ["Italic" markdown-insert-italic]
1098 ["Blockquote" markdown-insert-blockquote]
1099 ["Preformatted" markdown-insert-pre]
1100 ["Code" markdown-insert-code]
1101 "---"
1102 ["Insert inline link" markdown-insert-link]
1103 ["Insert image" markdown-insert-image]
1104 ["Insert horizontal rule" markdown-insert-hr]
1105 "---"
1106 ["Check references" markdown-check-refs]
1107 "---"
1108 ["Version" markdown-show-version]
1113 ;;; References ================================================================
1115 ;;; Undefined reference checking code by Dmitry Dzhus <mail@sphinx.net.ru>.
1117 (defconst markdown-refcheck-buffer
1118 "*Undefined references for %BUFFER%*"
1119 "Pattern for name of buffer for listing undefined references.
1120 The string %BUFFER% will be replaced by the corresponding
1121 `markdown-mode' buffer name.")
1123 (defun markdown-has-reference-definition (reference)
1124 "Find out whether Markdown REFERENCE is defined.
1126 REFERENCE should include the square brackets, like [this]."
1127 (let ((reference (downcase reference)))
1128 (save-excursion
1129 (goto-char (point-min))
1130 (catch 'found
1131 (while (re-search-forward markdown-regex-reference-definition nil t)
1132 (when (string= reference (downcase (match-string-no-properties 1)))
1133 (throw 'found t)))))))
1135 (defun markdown-get-undefined-refs ()
1136 "Return a list of undefined Markdown references.
1138 Result is an alist of pairs (reference . occurencies), where
1139 occurencies is itself another alist of pairs (label .
1140 line-number).
1142 For example, an alist corresponding to [Nice editor][Emacs] at line 12,
1143 \[GNU Emacs][Emacs] at line 45 and [manual][elisp] at line 127 is
1144 \((\"[emacs]\" (\"[Nice editor]\" . 12) (\"[GNU Emacs]\" . 45)) (\"[elisp]\" (\"[manual]\" . 127)))."
1145 (let ((missing))
1146 (save-excursion
1147 (goto-char (point-min))
1148 (while
1149 (re-search-forward markdown-regex-link-reference nil t)
1150 (let* ((label (match-string-no-properties 1))
1151 (reference (match-string-no-properties 2))
1152 (target (downcase (if (string= reference "[]") label reference))))
1153 (unless (markdown-has-reference-definition target)
1154 (let ((entry (assoc target missing)))
1155 (if (not entry)
1156 (add-to-list 'missing (cons target
1157 (list (cons label (markdown-line-number-at-pos)))) t)
1158 (setcdr entry
1159 (append (cdr entry) (list (cons label (markdown-line-number-at-pos))))))))))
1160 missing)))
1162 (defun markdown-add-missing-ref-definition (ref buffer &optional recheck)
1163 "Add blank REF definition to the end of BUFFER.
1165 REF is a Markdown reference in square brackets, like \"[lisp-history]\".
1167 When RECHECK is non-nil, BUFFER gets rechecked for undefined
1168 references so that REF disappears from the list of those links."
1169 (with-current-buffer buffer
1170 (when (not (eq major-mode 'markdown-mode))
1171 (error "Not available in current mode"))
1172 (goto-char (point-max))
1173 (indent-new-comment-line)
1174 (insert (concat ref ": ")))
1175 (switch-to-buffer-other-window buffer)
1176 (goto-char (point-max))
1177 (when recheck
1178 (markdown-check-refs t)))
1180 ;; Button which adds an empty Markdown reference definition to the end
1181 ;; of buffer specified as its 'target-buffer property. Reference name
1182 ;; is button's label
1183 (when (>= emacs-major-version 22)
1184 (define-button-type 'markdown-ref-button
1185 'help-echo "Push to create an empty reference definition"
1186 'face 'bold
1187 'action (lambda (b)
1188 (markdown-add-missing-ref-definition
1189 (button-label b) (button-get b 'target-buffer) t))))
1191 ;; Button jumping to line in buffer specified as its 'target-buffer
1192 ;; property. Line number is button's 'line property.
1193 (when (>= emacs-major-version 22)
1194 (define-button-type 'goto-line-button
1195 'help-echo "Push to go to this line"
1196 'face 'italic
1197 'action (lambda (b)
1198 (message (button-get b 'buffer))
1199 (switch-to-buffer-other-window (button-get b 'target-buffer))
1200 ;; use call-interactively to silence compiler
1201 (call-interactively 'goto-line (button-get b 'target-line)))))
1203 (defun markdown-check-refs (&optional silent)
1204 "Show all undefined Markdown references in current `markdown-mode' buffer.
1206 If SILENT is non-nil, do not message anything when no undefined
1207 references found.
1209 Links which have empty reference definitions are considered to be
1210 defined."
1211 (interactive "P")
1212 (when (not (eq major-mode 'markdown-mode))
1213 (error "Not available in current mode"))
1214 (let ((oldbuf (current-buffer))
1215 (refs (markdown-get-undefined-refs))
1216 (refbuf (get-buffer-create (replace-regexp-in-string
1217 "%BUFFER%" (buffer-name)
1218 markdown-refcheck-buffer t))))
1219 (if (null refs)
1220 (progn
1221 (when (not silent)
1222 (message "No undefined references found"))
1223 (kill-buffer refbuf))
1224 (with-current-buffer refbuf
1225 (when view-mode
1226 (View-exit-and-edit))
1227 (erase-buffer)
1228 (insert "Following references lack definitions:")
1229 (newline 2)
1230 (dolist (ref refs)
1231 (let ((button-label (format "%s" (car ref))))
1232 (if (>= emacs-major-version 22)
1233 ;; Create a reference button in Emacs 22
1234 (insert-text-button button-label
1235 :type 'markdown-ref-button
1236 'target-buffer oldbuf)
1237 ;; Insert reference as text in Emacs < 22
1238 (insert button-label)))
1239 (insert " (")
1240 (dolist (occurency (cdr ref))
1241 (let ((line (cdr occurency)))
1242 (if (>= emacs-major-version 22)
1243 ;; Create a line number button in Emacs 22
1244 (insert-button (number-to-string line)
1245 :type 'goto-line-button
1246 'target-buffer oldbuf
1247 'target-line line)
1248 ;; Insert line number as text in Emacs < 22
1249 (insert (number-to-string line)))
1250 (insert " "))) (delete-char -1)
1251 (insert ")")
1252 (newline))
1253 (view-buffer-other-window refbuf)
1254 (goto-char (point-min))
1255 (forward-line 2)))))
1258 ;;; Outline ===================================================================
1260 ;; The following visibility cycling code was taken from org-mode
1261 ;; by Carsten Dominik and adapted for markdown-mode.
1263 (defvar markdown-cycle-global-status 1)
1264 (defvar markdown-cycle-subtree-status nil)
1266 ;; Based on org-end-of-subtree from org.el
1267 (defun markdown-end-of-subtree (&optional invisible-OK)
1268 "Move to the end of the current subtree.
1269 Only visible heading lines are considered, unless INVISIBLE-OK is
1270 non-nil."
1271 (outline-back-to-heading invisible-OK)
1272 (let ((first t)
1273 (level (funcall outline-level)))
1274 (while (and (not (eobp))
1275 (or first (> (funcall outline-level) level)))
1276 (setq first nil)
1277 (outline-next-heading))
1278 (if (memq (preceding-char) '(?\n ?\^M))
1279 (progn
1280 ;; Go to end of line before heading
1281 (forward-char -1)
1282 (if (memq (preceding-char) '(?\n ?\^M))
1283 ;; leave blank line before heading
1284 (forward-char -1)))))
1285 (point))
1287 ;; Based on org-cycle from org.el.
1288 (defun markdown-cycle (&optional arg)
1289 "Visibility cycling for Markdown mode.
1290 If ARG is t, perform global visibility cycling. If the point is
1291 at an atx-style header, cycle visibility of the corresponding
1292 subtree. Otherwise, insert a tab using `indent-relative'."
1293 (interactive "P")
1294 (cond
1295 ((eq arg t) ;; Global cycling
1296 (cond
1297 ((and (eq last-command this-command)
1298 (eq markdown-cycle-global-status 2))
1299 ;; Move from overview to contents
1300 (hide-sublevels 1)
1301 (message "CONTENTS")
1302 (setq markdown-cycle-global-status 3))
1304 ((and (eq last-command this-command)
1305 (eq markdown-cycle-global-status 3))
1306 ;; Move from contents to all
1307 (show-all)
1308 (message "SHOW ALL")
1309 (setq markdown-cycle-global-status 1))
1312 ;; Defaults to overview
1313 (hide-body)
1314 (message "OVERVIEW")
1315 (setq markdown-cycle-global-status 2))))
1317 ((save-excursion (beginning-of-line 1) (looking-at outline-regexp))
1318 ;; At a heading: rotate between three different views
1319 (outline-back-to-heading)
1320 (let ((goal-column 0) eoh eol eos)
1321 ;; Determine boundaries
1322 (save-excursion
1323 (outline-back-to-heading)
1324 (save-excursion
1325 (beginning-of-line 2)
1326 (while (and (not (eobp)) ;; this is like `next-line'
1327 (get-char-property (1- (point)) 'invisible))
1328 (beginning-of-line 2)) (setq eol (point)))
1329 (outline-end-of-heading) (setq eoh (point))
1330 (markdown-end-of-subtree t)
1331 (skip-chars-forward " \t\n")
1332 (beginning-of-line 1) ; in case this is an item
1333 (setq eos (1- (point))))
1334 ;; Find out what to do next and set `this-command'
1335 (cond
1336 ((= eos eoh)
1337 ;; Nothing is hidden behind this heading
1338 (message "EMPTY ENTRY")
1339 (setq markdown-cycle-subtree-status nil))
1340 ((>= eol eos)
1341 ;; Entire subtree is hidden in one line: open it
1342 (show-entry)
1343 (show-children)
1344 (message "CHILDREN")
1345 (setq markdown-cycle-subtree-status 'children))
1346 ((and (eq last-command this-command)
1347 (eq markdown-cycle-subtree-status 'children))
1348 ;; We just showed the children, now show everything.
1349 (show-subtree)
1350 (message "SUBTREE")
1351 (setq markdown-cycle-subtree-status 'subtree))
1353 ;; Default action: hide the subtree.
1354 (hide-subtree)
1355 (message "FOLDED")
1356 (setq markdown-cycle-subtree-status 'folded)))))
1359 (message "TAB")
1360 (funcall indent-line-function))))
1362 ;; Based on org-shifttab from org.el.
1363 (defun markdown-shifttab ()
1364 "Global visibility cycling.
1365 Calls `markdown-cycle' with argument t."
1366 (interactive)
1367 (markdown-cycle t))
1369 ;;; Commands ==================================================================
1371 (defun markdown ()
1372 "Run markdown on the current buffer and preview the output in another buffer."
1373 (interactive)
1374 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
1375 (shell-command-on-region (region-beginning) (region-end) markdown-command
1376 "*markdown-output*" nil)
1377 (shell-command-on-region (point-min) (point-max) markdown-command
1378 "*markdown-output*" nil))
1379 (let (title)
1380 (setq title (buffer-name))
1381 (save-current-buffer
1382 (set-buffer "*markdown-output*")
1383 (goto-char (point-min))
1384 (insert "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
1385 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
1386 "\t\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n"
1387 "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\n"
1388 "<head>\n<title>")
1389 (insert title)
1390 (insert "</title>\n")
1391 (if markdown-css-path
1392 (insert "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\""
1393 markdown-css-path
1394 "\" />\n"))
1395 (insert "</head>\n\n"
1396 "<body>\n\n")
1397 (goto-char (point-max))
1398 (insert "\n"
1399 "</body>\n"
1400 "</html>\n"))))
1402 (defun markdown-preview ()
1403 "Run markdown on the current buffer and preview the output in a browser."
1404 (interactive)
1405 (markdown)
1406 (browse-url-of-buffer "*markdown-output*"))
1409 ;;; Miscellaneous =============================================================
1411 (defun markdown-line-number-at-pos (&optional pos)
1412 "Return (narrowed) buffer line number at position POS.
1413 If POS is nil, use current buffer location.
1414 This is an exact copy of `line-number-at-pos' for use in emacs21."
1415 (let ((opoint (or pos (point))) start)
1416 (save-excursion
1417 (goto-char (point-min))
1418 (setq start (point))
1419 (goto-char opoint)
1420 (forward-line 0)
1421 (1+ (count-lines start (point))))))
1423 (defun markdown-nobreak-p ()
1424 "Return nil if it is acceptable to break the current line at the point."
1425 ;; inside in square brackets (e.g., link anchor text)
1426 (looking-back "\\[[^]]*"))
1430 ;;; Mode definition ==========================================================
1432 (defun markdown-show-version ()
1433 "Show the version number in the minibuffer."
1434 (interactive)
1435 (message "markdown-mode, version %s" markdown-mode-version))
1437 ;;;###autoload
1438 (define-derived-mode markdown-mode text-mode "Markdown"
1439 "Major mode for editing Markdown files."
1440 ;; Comments
1441 (make-local-variable 'comment-start)
1442 (setq comment-start "<!-- ")
1443 (make-local-variable 'comment-end)
1444 (setq comment-end " -->")
1445 (make-local-variable 'comment-start-skip)
1446 (setq comment-start-skip "<!--[ \t]*")
1447 (make-local-variable 'comment-column)
1448 (setq comment-column 0)
1449 ;; Font lock.
1450 (set (make-local-variable 'font-lock-defaults)
1451 '(markdown-mode-font-lock-keywords))
1452 (set (make-local-variable 'font-lock-multiline) t)
1453 ;; For menu support in XEmacs
1454 (easy-menu-add markdown-mode-menu markdown-mode-map)
1455 ;; Make filling work with lists (unordered, ordered, and definition)
1456 (set (make-local-variable 'paragraph-start)
1457 "\f\\|[ \t]*$\\|^[ \t]*[*+-] \\|^[ \t*][0-9]+\\.\\|^[ \t]*: ")
1458 ;; Outline mode
1459 (make-local-variable 'outline-regexp)
1460 (setq outline-regexp "#+")
1461 ;; Cause use of ellipses for invisible text.
1462 (add-to-invisibility-spec '(outline . t))
1463 ;; Indentation and filling
1464 (make-local-variable 'fill-nobreak-predicate)
1465 (add-hook 'fill-nobreak-predicate 'markdown-nobreak-p)
1466 (setq indent-line-function markdown-indent-function))
1468 ;(add-to-list 'auto-mode-alist '("\\.text$" . markdown-mode))
1470 (provide 'markdown-mode)
1472 ;;; markdown-mode.el ends here