Markdown Mode 1.6
[markdown-mode/intrigeri.git] / markdown-mode.el
blob9378ac6068e58d8ca5f20a40eeb26e0e34cd4d06
1 ;;; markdown-mode.el --- Major mode to edit Markdown files in Emacs
3 ;; Copyright (C) 2007, 2008 Jason Blevins
5 ;; Version: 1.6
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 version is markdown-mode 1.6, released on June 4. 2008:
36 ;; * [markdown-mode.el][]
37 ;; * [Screenshot][]
38 ;; * [Release notes][]
40 ;; markdown-mode is also available in the Debian `emacs-goodies-el`
41 ;; package (beginning with revision 27.0-1).
43 ;; [markdown-mode.el]: http://code.jblevins.org/markdown-mode/markdown-mode.el
44 ;; [screenshot]: http://jblevins.org/projects/markdown-mode/screenshots/20080604-001.png
45 ;; [release notes]: http://jblevins.org/projects/markdown-mode/rev-1-6
47 ;;; Dependencies:
49 ;; markdown-mode requires easymenu, a standard package since GNU Emacs
50 ;; 19 and XEmacs 19, which provides a uniform interface for creating
51 ;; menus in GNU Emacs and XEmacs.
53 ;;; Installation:
55 ;; Make sure to place `markdown-mode.el` somewhere in the load-path and add
56 ;; the following lines to your `.emacs` file to associate markdown-mode
57 ;; with `.text` files:
59 ;; (autoload 'markdown-mode "markdown-mode.el"
60 ;; "Major mode for editing Markdown files" t)
61 ;; (setq auto-mode-alist
62 ;; (cons '("\\.text" . markdown-mode) auto-mode-alist))
64 ;; There is no consensus on an official file extension so change `.text` to
65 ;; `.mdwn`, `.md`, `.mdt`, or whatever you call your markdown files.
67 ;;; Usage:
69 ;; Although no configuration is necessary there are a few things that can
70 ;; be customized (`M-x customize-mode`).
72 ;; Keybindings are grouped by prefixes based on their function. For
73 ;; example, commands dealing with headers begin with `C-c C-t`. The
74 ;; primary commands in each group will are described below. You can
75 ;; obtain a list of all keybindings by pressing `C-c C-h`.
77 ;; * Anchors: `C-c C-a`
79 ;; `C-c C-a l` inserts inline links of the form `[text](url)`. If
80 ;; there is an active region, text in the region is used for the link
81 ;; text. `C-c C-a w` acts similarly for wiki links of the form
82 ;; `[[WikiLink]]`.
84 ;; * Commands: `C-c C-c`
86 ;; `C-c C-c m` will run Markdown on the current buffer and preview the
87 ;; output in another buffer while `C-c C-c p` runs Markdown on the
88 ;; current buffer and previews the output in a browser.
90 ;; `C-c C-c c` will check for undefined references. If there are any,
91 ;; a small buffer will open with a list of undefined references and
92 ;; the line numbers on which they appear. In Emacs 22 and greater,
93 ;; selecting a reference from this list and pressing `RET` will insert
94 ;; an empty reference definition at the end of the buffer. Similarly,
95 ;; selecting the line number will jump to the corresponding line.
97 ;; * Images: `C-c C-i`
99 ;; `C-c C-i i` inserts an image, using the active region (if any) as
100 ;; the alt text.
102 ;; * Physical styles: `C-c C-p`
104 ;; These commands all act on text in the active region, if any, and
105 ;; insert empty markup fragments otherwise. `C-c C-p b` makes the
106 ;; selected text bold, `C-c C-p f` formats the region as fixed-width
107 ;; text, and `C-c C-p i` is used for italic text.
109 ;; * Logical styles: `C-c C-s`
111 ;; These commands all act on text in the active region, if any, and
112 ;; insert empty markup fragments otherwise. Logical styles include
113 ;; blockquote (`C-c C-s b`), preformatted (`C-c C-s p`), code (`C-c C-s c`),
114 ;; emphasis (`C-c C-s e`), and strong (`C-c C-s s`).
116 ;; * Headers: `C-c C-t`
118 ;; All header commands use text in the active region, if any, as the
119 ;; header text. To insert an atx or hash style level-n header, press
120 ;; `C-c C-t n` where n is between 1 and 5. For a top-level setext or
121 ;; underline style header press `C-c C-t t` (mnemonic: title) and for
122 ;; a second-level underline-style header press `C-c C-t s`
123 ;; (mnemonic: section).
125 ;; * Other commands
127 ;; `C-c -` inserts a horizontal rule.
129 ;; Many of the commands described above behave differently depending on
130 ;; whether Transient Mark mode is enabled or not. When it makes sense,
131 ;; if Transient Mark mode is on and a region is active, the command
132 ;; applies to the text in the region (e.g., `C-c C-p b` makes the region
133 ;; bold). For users who prefer to work outside of Transient Mark mode,
134 ;; in Emacs 22 it can be enabled temporarily by pressing `C-SPC C-SPC`.
136 ;; When applicable, commands that specifically act on the region even
137 ;; outside of Transient Mark mode have the same keybinding as the with
138 ;; the exception of an additional `C-` prefix. For example,
139 ;; `markdown-insert-blockquote` is bound to `C-c C-s b` and only acts on
140 ;; the region in Transient Mark mode while `markdown-blockquote-region`
141 ;; is bound to `C-c C-s C-b` and always applies to the region (when
142 ;; nonempty).
144 ;; Markdown mode supports outline-minor-mode as well as org-mode-style
145 ;; visibility cycling for atx- or hash-style headers. There are two
146 ;; types of visibility cycling: Pressing `S-TAB` cycles globally between
147 ;; the table of contents view (headers only), outline view (top-level
148 ;; headers only), and the full document view. Pressing `TAB` while the
149 ;; point is at a header will cycle through levels of visibility for the
150 ;; subtree: completely folded, visiable children, and fully visible.
151 ;; Note that mixing hash and underline style headers will give undesired
152 ;; results.
154 ;;; Extensions:
156 ;; Besides supporting the basic Markdown syntax, markdown-mode also
157 ;; includes syntax highlighting for `[[Wiki Links]]` by default.
159 ;; [SmartyPants][] support is possible by customizing `markdown-command`.
160 ;; If you install `SmartyPants.pl` at, say, `/usr/local/bin/smartypants`,
161 ;; then you can set `markdown-command` to `"markdown | smartypants"`.
162 ;; You can do this either by using `M-x customize-group markdown`
163 ;; or by placing the following in your `.emacs` file:
165 ;; (defun markdown-custom ()
166 ;; "markdown-mode-hook"
167 ;; (setq markdown-command "markdown | smartypants"))
168 ;; (add-hook 'markdown-mode-hook '(lambda() (markdown-custom)))
170 ;; Experimental syntax highlighting for mathematical expressions written
171 ;; in LaTeX (only expressions denoted by `$..$`, `$$..$$`, or `\[..\]`)
172 ;; can be enabled by editing `markdown-mode.el` and changing `(defvar
173 ;; markdown-enable-itex nil)` to `(defvar markdown-enable-itex t)`.
175 ;; [SmartyPants]: http://daringfireball.net/projects/smartypants/
177 ;;; Thanks:
179 ;; * Cyril Brulebois <cyril.brulebois@enst-bretagne.fr> for Debian packaging.
180 ;; * Conal Elliott <conal@conal.net> for a font-lock regexp patch.
181 ;; * Edward O'Connor <hober0@gmail.com> for a font-lock regexp fix.
182 ;; * Greg Bognar <greg_bognar@hms.harvard.edu> for menus and a patch.
183 ;; * Daniel Burrows <dburrows@debian.org> for filing Debian bug #456592.
184 ;; * Peter S. Galbraith <psg@debian.org> for maintaining emacs-goodies-el.
185 ;; * Dmitry Dzhus <mail@sphinx.net.ru> for reference checking functions.
187 ;;; Bugs:
189 ;; Markdown mode is developed and tested primarily using GNU Emacs 22
190 ;; although compatibility with GNU Emacs 21 is also a priority.
192 ;; Presently Markdown mode does not attempt to distinguish between
193 ;; multiple indentation levels and preformatted text (four or more
194 ;; leading spaces). I am not aware of a way to handle this using
195 ;; Emacs's regexp-based font-lock facilities. Implementing a more
196 ;; robust approach to syntax highlighting is a high-priority item for
197 ;; future work.
199 ;; If you find any bugs, such as syntax highlighting issues, please
200 ;; construct a test case and email me at <jrblevin@sdf.lonestar.org>.
201 ;; Comments and patches are welcome!
205 ;;; Code:
207 (require 'easymenu)
208 (require 'outline)
210 ;;; User Customizable Variables ===============================================
212 ;; To enable LaTeX/itex syntax highlighting, change to
213 ;; (defvar markdown-enable-itex t)
214 (defvar markdown-enable-itex nil)
217 ;;; Customizable variables ====================================================
219 ;; Current revision
220 (defconst markdown-mode-version "1.6")
222 ;; A hook for users to run their own code when the mode is loaded.
223 (defvar markdown-mode-hook nil)
226 ;;; Customizable variables ====================================================
228 (defgroup markdown nil
229 "Major mode for editing text files in Markdown format."
230 :prefix "markdown-"
231 :group 'wp
232 :link '(url-link "http://jblevins.org/projects/markdown-mode/"))
234 (defcustom markdown-command "markdown"
235 "Command to run markdown."
236 :group 'markdown
237 :type 'string)
239 (defcustom markdown-hr-length 5
240 "Length of horizonal rules."
241 :group 'markdown
242 :type 'integer)
244 (defcustom markdown-bold-underscore nil
245 "Use two underscores for bold instead of two asterisks."
246 :group 'markdown
247 :type 'boolean)
249 (defcustom markdown-italic-underscore nil
250 "Use underscores for italic instead of asterisks."
251 :group 'markdown
252 :type 'boolean)
255 ;;; Font lock =================================================================
257 (require 'font-lock)
259 (defgroup markdown-faces nil
260 "Faces used in Markdown Mode"
261 :group 'markdown
262 :group 'faces)
264 (defcustom markdown-italic-face 'font-lock-variable-name-face
265 "Italic text."
266 :group 'markdown-faces
267 :type '(face))
269 (defcustom markdown-bold-face 'font-lock-type-face
270 "Bold text"
271 :group 'markdown-faces
272 :type '(face))
274 (defcustom markdown-header-face 'font-lock-function-name-face
275 "Headers"
276 :group 'markdown-faces
277 :type '(face))
279 (defcustom markdown-inline-code-face 'font-lock-builtin-face
280 "Inline code"
281 :group 'markdown-faces
282 :type '(face))
284 (defcustom markdown-list-face 'font-lock-variable-name-face
285 "List item markers"
286 :group 'markdown-faces
287 :type '(face))
289 (defcustom markdown-blockquote-face 'font-lock-comment-face
290 "Blockquote sections and preformatted text"
291 :group 'markdown-faces
292 :type '(face))
294 (defcustom markdown-link-face 'font-lock-constant-face
295 "Link text"
296 :group 'markdown-faces
297 :type '(face))
299 (defcustom markdown-reference-face 'font-lock-type-face
300 "Link references"
301 :group 'markdown-faces
302 :type '(face))
304 (defcustom markdown-url-face 'font-lock-string-face
305 "URLs"
306 :group 'markdown-faces
307 :type '(face))
309 (defcustom markdown-math-face 'font-lock-builtin-face
310 "LaTeX expressions"
311 :group 'markdown-faces
312 :type '(face))
314 (defconst markdown-regex-link-inline
315 "\\(!?\\[[^]]*?\\]\\)\\(([^\\)]*)\\)"
316 "Regular expression for a [text](file) or an image link ![text](file)")
318 (defconst markdown-regex-link-reference
319 "\\(!?\\[[^]]+?\\]\\)[ ]?\\(\\[[^]]*?\\]\\)"
320 "Regular expression for a reference link [text][id]")
322 (defconst markdown-regex-reference-definition
323 "^ \\{0,3\\}\\(\\[.+?\\]\\):\\s *\\(.*?\\)\\s *\\( \"[^\"]*\"$\\|$\\)"
324 "Regular expression for a link definition [id]: ...")
326 (defconst markdown-regex-header-atx
327 "^\\(#+ \\)\\(.*?\\)\\($\\| #+$\\)"
328 "Regular expression for atx-style (hash mark) headers")
330 (defconst markdown-regex-header-setext
331 "^\\(.*\\)\n\\(===+\\|---+\\)$"
332 "Regular expression for setext-style (underline) headers")
334 (defconst markdown-regex-hr
335 "^\\(\\*[ ]?\\*[ ]?\\*[ ]?[\\* ]*\\|-[ ]?-[ ]?-[--- ]*\\)$"
336 "Regular expression for matching Markdown horizontal rules")
338 (defconst markdown-regex-code
339 "\\(^\\|[^\\]\\)\\(\\(`\\{1,2\\}\\)\\([^ \\]\\|[^ ].*?[^ \\]\\)\\3\\)"
340 "Regular expression for matching inline code fragments")
342 (defconst markdown-regex-pre
343 "^ .*$"
344 "Regular expression for matching preformatted text sections")
346 (defconst markdown-regex-list
347 "^[ \t]*\\([0-9]+\\.\\|[\\*\\+-]\\) "
348 "Regular expression for matching list markers")
350 (defconst markdown-regex-bold
351 "\\(^\\|[^\\]\\)\\(\\([*_]\\{2\\}\\)\\(.\\|\n\\)*?[^\\ ]\\3\\)"
352 "Regular expression for matching bold text")
354 (defconst markdown-regex-italic
355 "\\(^\\|[^\\]\\)\\(\\([*_]\\)\\([^ \\]\\3\\|[^ ]\\(.\\|\n\\)*?[^\\ ]\\3\\)\\)"
356 "Regular expression for matching italic text")
358 (defconst markdown-regex-blockquote
359 "^>.*$"
360 "Regular expression for matching blockquote lines")
362 (defconst markdown-regex-line-break
363 " $"
364 "Regular expression for matching line breaks")
366 (defconst markdown-regex-wiki-link
367 "\\[\\[[^]]+\\]\\]"
368 "Regular expression for matching wiki links")
370 (defconst markdown-regex-uri
371 "<\\(acap\\|cid\\|data\\|dav\\|fax\\|file\\|ftp\\|gopher\\|http\\|https\\|imap\\|ldap\\|mailto\\|mid\\|modem\\|news\\|nfs\\|nntp\\|pop\\|prospero\\|rtsp\\|service\\|sip\\|tel\\|telnet\\|tip\\|urn\\|vemmi\\|wais\\)://[^>]*>"
372 "Regular expression for matching inline URIs")
374 (defconst markdown-regex-email
375 "<\\(\\sw\\|\\s_\\|\\s.\\)+@\\(\\sw\\|\\s_\\|\\s.\\)+>"
376 "Regular expression for matching inline email addresses")
378 (defconst markdown-regex-latex-expression
379 "\\(^\\|[^\\]\\)\\(\\$\\($\\([^\\$]\\|\\\\.\\)*\\$\\|\\([^\\$]\\|\\\\.\\)*\\)\\$\\)"
380 "Regular expression for itex $..$ or $$..$$ math mode expressions")
382 (defconst markdown-regex-latex-display
383 "^\\\\\\[\\(.\\|\n\\)*?\\\\\\]$"
384 "Regular expression for itex \[..\] display mode expressions")
386 (defconst markdown-mode-font-lock-keywords-basic
387 (list
388 (cons markdown-regex-code '(2 markdown-inline-code-face))
389 (cons markdown-regex-pre markdown-blockquote-face)
390 (cons markdown-regex-header-setext markdown-header-face)
391 (cons markdown-regex-header-atx markdown-header-face)
392 (cons markdown-regex-list markdown-list-face)
393 (cons markdown-regex-hr markdown-header-face)
394 (cons markdown-regex-link-inline
395 '((1 markdown-link-face t)
396 (2 markdown-url-face t)))
397 (cons markdown-regex-link-reference
398 '((1 markdown-link-face t)
399 (2 markdown-reference-face t)))
400 (cons markdown-regex-reference-definition
401 '((1 markdown-reference-face t)
402 (2 markdown-url-face t)
403 (3 markdown-link-face t)))
404 (cons markdown-regex-bold '(2 markdown-bold-face))
405 (cons markdown-regex-italic '(2 markdown-italic-face))
406 (cons markdown-regex-blockquote markdown-blockquote-face)
407 (cons markdown-regex-wiki-link markdown-link-face)
408 (cons markdown-regex-uri markdown-link-face)
409 (cons markdown-regex-email markdown-link-face))
410 "Syntax highlighting for Markdown files.")
413 ;; Includes additional Latex/itex/Instiki font lock keywords
414 (defconst markdown-mode-font-lock-keywords-itex
415 (append
416 (list
417 ;; itex math mode $..$ or $$..$$
418 (cons markdown-regex-latex-expression '(2 markdown-math-face))
419 ;; Display mode equations with brackets: \[ \]
420 (cons markdown-regex-latex-display markdown-math-face)
421 ;; Equation reference (eq:foo)
422 (cons "(eq:\\w+)" markdown-reference-face)
423 ;; Equation reference \eqref
424 (cons "\\\\eqref{\\w+}" markdown-reference-face))
425 markdown-mode-font-lock-keywords-basic)
426 "Syntax highlighting for Markdown, itex, and wiki expressions.")
429 (defvar markdown-mode-font-lock-keywords
430 (if markdown-enable-itex
431 markdown-mode-font-lock-keywords-itex
432 markdown-mode-font-lock-keywords-basic)
433 "Default highlighting expressions for Markdown mode")
437 ;;; Syntax Table ==============================================================
439 (defvar markdown-mode-syntax-table
440 (let ((markdown-mode-syntax-table (make-syntax-table)))
441 (modify-syntax-entry ?\" "w" markdown-mode-syntax-table)
442 markdown-mode-syntax-table)
443 "Syntax table for markdown-mode")
447 ;;; Element Insertion =========================================================
449 (defun markdown-wrap-or-insert (s1 s2)
450 "Insert the strings S1 and S2.
451 If Transient Mark mode is on and a region is active, wrap the strings S1
452 and S2 around the region."
453 (if (and transient-mark-mode mark-active)
454 (let ((a (region-beginning)) (b (region-end)))
455 (goto-char a)
456 (insert s1)
457 (goto-char (+ b (length s1)))
458 (insert s2))
459 (insert s1 s2)))
461 (defun markdown-insert-hr ()
462 "Inserts a horizonal rule."
463 (interactive)
464 (let (hr)
465 (dotimes (count (- markdown-hr-length 1) hr) ; Count to n - 1
466 (setq hr (concat "* " hr))) ; Build HR string
467 (setq hr (concat hr "*\n")) ; Add the n-th *
468 (insert hr)))
470 (defun markdown-insert-bold ()
471 "Inserts markup for a bold word or phrase.
472 If Transient Mark mode is on and a region is active, it is made bold."
473 (interactive)
474 (if markdown-bold-underscore
475 (markdown-wrap-or-insert "__" "__")
476 (markdown-wrap-or-insert "**" "**"))
477 (backward-char 2))
479 (defun markdown-insert-italic ()
480 "Inserts markup for an italic word or phrase.
481 If Transient Mark mode is on and a region is active, it is made italic."
482 (interactive)
483 (if markdown-italic-underscore
484 (markdown-wrap-or-insert "_" "_")
485 (markdown-wrap-or-insert "*" "*"))
486 (backward-char 1))
488 (defun markdown-insert-code ()
489 "Inserts markup for an inline code fragment.
490 If Transient Mark mode is on and a region is active, it is marked
491 as inline code."
492 (interactive)
493 (markdown-wrap-or-insert "`" "`")
494 (backward-char 1))
496 (defun markdown-insert-link ()
497 "Inserts an inline link of the form []().
498 If Transient Mark mode is on and a region is active, it is used
499 as the link text."
500 (interactive)
501 (markdown-wrap-or-insert "[" "]")
502 (insert "()")
503 (backward-char 1))
505 (defun markdown-insert-wiki-link ()
506 "Inserts a wiki link of the form [[WikiLink]].
507 If Transient Mark mode is on and a region is active, it is used
508 as the link text."
509 (interactive)
510 (markdown-wrap-or-insert "[[" "]]")
511 (backward-char 2))
513 (defun markdown-insert-image ()
514 "Inserts an inline image tag of the form ![]().
515 If Transient Mark mode is on and a region is active, it is used
516 as the alt text of the image."
517 (interactive)
518 (markdown-wrap-or-insert "![" "]")
519 (insert "()")
520 (backward-char 1))
522 (defun markdown-insert-header-1 ()
523 "Inserts a first level atx-style (hash mark) header.
524 If Transient Mark mode is on and a region is active, it is used
525 as the header text."
526 (interactive)
527 (markdown-insert-header 1))
529 (defun markdown-insert-header-2 ()
530 "Inserts a second level atx-style (hash mark) header.
531 If Transient Mark mode is on and a region is active, it is used
532 as the header text."
533 (interactive)
534 (markdown-insert-header 2))
536 (defun markdown-insert-header-3 ()
537 "Inserts a third level atx-style (hash mark) header.
538 If Transient Mark mode is on and a region is active, it is used
539 as the header text."
540 (interactive)
541 (markdown-insert-header 3))
543 (defun markdown-insert-header-4 ()
544 "Inserts a fourth level atx-style (hash mark) header.
545 If Transient Mark mode is on and a region is active, it is used
546 as the header text."
547 (interactive)
548 (markdown-insert-header 4))
550 (defun markdown-insert-header-5 ()
551 "Inserts a fifth level atx-style (hash mark) header.
552 If Transient Mark mode is on and a region is active, it is used
553 as the header text."
554 (interactive)
555 (markdown-insert-header 5))
557 (defun markdown-insert-header (n)
558 "Inserts an atx-style (hash mark) header.
559 With no prefix argument, insert a level-1 header. With prefix N,
560 insert a level-N header. If Transient Mark mode is on and the
561 region is active, it is used as the header text."
562 (interactive "p")
563 (unless n ; Test to see if n is defined
564 (setq n 1)) ; Default to level 1 header
565 (let (hdr)
566 (dotimes (count n hdr)
567 (setq hdr (concat "#" hdr))) ; Build a hash mark header string
568 (setq hdrl (concat hdr " "))
569 (setq hdrr (concat " " hdr))
570 (markdown-wrap-or-insert hdrl hdrr))
571 (backward-char (+ 1 n)))
573 (defun markdown-insert-title ()
574 "Insert a setext-style (underline) first level header.
575 If Transient Mark mode is on and a region is active, it is used
576 as the header text."
577 (interactive)
578 (if (and transient-mark-mode mark-active)
579 (let ((a (region-beginning))
580 (b (region-end))
581 (len 0)
582 (hdr))
583 (setq len (- b a))
584 (dotimes (count len hdr)
585 (setq hdr (concat "=" hdr))) ; Build a === title underline
586 (end-of-line)
587 (insert "\n" hdr "\n"))
588 (insert "\n==========\n")
589 (backward-char 12)))
591 (defun markdown-insert-section ()
592 "Insert a setext-style (underline) second level header.
593 If Transient Mark mode is on and a region is active, it is used
594 as the header text."
595 (interactive)
596 (if (and transient-mark-mode mark-active)
597 (let ((a (region-beginning))
598 (b (region-end))
599 (len 0)
600 (hdr))
601 (setq len (- b a))
602 (dotimes (count len hdr)
603 (setq hdr (concat "-" hdr))) ; Build a --- section underline
604 (end-of-line)
605 (insert "\n" hdr "\n"))
606 (insert "\n----------\n")
607 (backward-char 12)))
609 (defun markdown-insert-blockquote ()
610 "Start a blockquote section (or blockquote the region).
611 If Transient Mark mode is on and a region is active, it is used as
612 the blockquote text."
613 (interactive)
614 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
615 (markdown-blockquote-region)
616 (insert "> ")))
618 (defun markdown-blockquote-region (beg end &optional arg)
619 "Blockquote the region."
620 (interactive "*r\nP")
621 (if mark-active
622 (perform-replace "^" "> " nil 1 nil nil nil beg end)))
624 (defun markdown-insert-pre ()
625 "Start a preformatted section (or apply to the region).
626 If Transient Mark mode is on and a region is active, it is marked
627 as preformatted text."
628 (interactive)
629 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
630 (markdown-pre-region)
631 (insert " ")))
633 (defun markdown-pre-region (beg end &optional arg)
634 "Format the region as preformatted text."
635 (interactive "*r\nP")
636 (if mark-active
637 (perform-replace "^" " " nil 1 nil nil nil beg end)))
642 ;;; Keymap ====================================================================
644 (defvar markdown-mode-map
645 (let ((markdown-mode-map (make-keymap)))
646 ;; Element insertion
647 (define-key markdown-mode-map "\C-c\C-al" 'markdown-insert-link)
648 (define-key markdown-mode-map "\C-c\C-aw" 'markdown-insert-wiki-link)
649 (define-key markdown-mode-map "\C-c\C-ii" 'markdown-insert-image)
650 (define-key markdown-mode-map "\C-c\C-t1" 'markdown-insert-header-1)
651 (define-key markdown-mode-map "\C-c\C-t2" 'markdown-insert-header-2)
652 (define-key markdown-mode-map "\C-c\C-t3" 'markdown-insert-header-3)
653 (define-key markdown-mode-map "\C-c\C-t4" 'markdown-insert-header-4)
654 (define-key markdown-mode-map "\C-c\C-t5" 'markdown-insert-header-5)
655 (define-key markdown-mode-map "\C-c\C-pb" 'markdown-insert-bold)
656 (define-key markdown-mode-map "\C-c\C-ss" 'markdown-insert-bold)
657 (define-key markdown-mode-map "\C-c\C-pi" 'markdown-insert-italic)
658 (define-key markdown-mode-map "\C-c\C-se" 'markdown-insert-italic)
659 (define-key markdown-mode-map "\C-c\C-pf" 'markdown-insert-code)
660 (define-key markdown-mode-map "\C-c\C-sc" 'markdown-insert-code)
661 (define-key markdown-mode-map "\C-c\C-sb" 'markdown-insert-blockquote)
662 (define-key markdown-mode-map "\C-c\C-s\C-b" 'markdown-blockquote-region)
663 (define-key markdown-mode-map "\C-c\C-sp" 'markdown-insert-pre)
664 (define-key markdown-mode-map "\C-c\C-s\C-p" 'markdown-pre-region)
665 (define-key markdown-mode-map "\C-c-" 'markdown-insert-hr)
666 (define-key markdown-mode-map "\C-c\C-tt" 'markdown-insert-title)
667 (define-key markdown-mode-map "\C-c\C-ts" 'markdown-insert-section)
668 ;; Visibility cycling
669 (define-key markdown-mode-map (kbd "<tab>") 'markdown-cycle)
670 (define-key markdown-mode-map (kbd "<S-iso-lefttab>") 'markdown-shifttab)
671 ;; Markdown functions
672 (define-key markdown-mode-map "\C-c\C-cm" 'markdown)
673 (define-key markdown-mode-map "\C-c\C-cp" 'markdown-preview)
674 ;; References
675 (define-key markdown-mode-map "\C-c\C-cc" 'markdown-check-refs)
676 markdown-mode-map)
677 "Keymap for Markdown major mode")
679 ;;; Menu ==================================================================
681 (easy-menu-define markdown-mode-menu markdown-mode-map
682 "Menu for Markdown mode"
683 '("Markdown"
684 ("Show/Hide"
685 ["Cycle visibility" markdown-cycle (outline-on-heading-p)]
686 ["Cycle global visibility" markdown-shifttab])
687 "---"
688 ["Compile" markdown]
689 ["Preview" markdown-preview]
690 "---"
691 ("Headers (setext)"
692 ["Insert Title" markdown-insert-title]
693 ["Insert Section" markdown-insert-section])
694 ("Headers (atx)"
695 ["First level" markdown-insert-header-1]
696 ["Second level" markdown-insert-header-2]
697 ["Third level" markdown-insert-header-3]
698 ["Fourth level" markdown-insert-header-4]
699 ["Fifth level" markdown-insert-header-5])
700 "---"
701 ["Bold" markdown-insert-bold]
702 ["Italic" markdown-insert-italic]
703 ["Blockquote" markdown-insert-blockquote]
704 ["Preformatted" markdown-insert-pre]
705 ["Code" markdown-insert-code]
706 "---"
707 ["Insert inline link" markdown-insert-link]
708 ["Insert image" markdown-insert-image]
709 ["Insert horizontal rule" markdown-insert-hr]
710 "---"
711 ["Check references" markdown-check-refs]
712 "---"
713 ["Version" markdown-show-version]
718 ;;; References ================================================================
720 ;;; Undefined reference checking code by Dmitry Dzhus <mail@sphinx.net.ru>.
722 (defconst markdown-refcheck-buffer
723 "*Undefined references for %BUFFER%*"
724 "Name of buffer which will contain a list of undefined
725 references in `markdown-mode' buffer named %BUFFER%.")
727 (defun markdown-has-reference-definition (reference)
728 "Find out whether Markdown REFERENCE is defined.
730 REFERENCE should include the square brackets, like [this]."
731 (let ((reference (downcase reference)))
732 (save-excursion
733 (goto-char (point-min))
734 (catch 'found
735 (while (re-search-forward markdown-regex-reference-definition nil t)
736 (when (string= reference (downcase (match-string-no-properties 1)))
737 (throw 'found t)))))))
739 (defun markdown-get-undefined-refs ()
740 "Return a list of undefined Markdown references.
742 Result is an alist of pairs (reference . occurencies), where
743 occurencies is itself another alist of pairs (label .
744 line-number).
746 For example, an alist corresponding to [Nice editor][Emacs] at line 12,
747 \[GNU Emacs][Emacs] at line 45 and [manual][elisp] at line 127 is
748 \((\"[emacs]\" (\"[Nice editor]\" . 12) (\"[GNU Emacs]\" . 45)) (\"[elisp]\" (\"[manual]\" . 127)))."
749 (let ((missing))
750 (save-excursion
751 (goto-char (point-min))
752 (while
753 (re-search-forward markdown-regex-link-reference nil t)
754 (let* ((label (match-string-no-properties 1))
755 (reference (match-string-no-properties 2))
756 (target (downcase (if (string= reference "[]") label reference))))
757 (unless (markdown-has-reference-definition target)
758 (let ((entry (assoc target missing)))
759 (if (not entry)
760 (add-to-list 'missing (cons target
761 (list (cons label (markdown-line-number-at-pos)))) t)
762 (setcdr entry
763 (append (cdr entry) (list (cons label (markdown-line-number-at-pos))))))))))
764 missing)))
766 (defun markdown-add-missing-ref-definition (ref buffer &optional recheck)
767 "Add blank REF definition to the end of BUFFER.
769 REF is a Markdown reference in square brackets, like \"[lisp-history]\".
771 When RECHECK is non-nil, BUFFER gets rechecked for undefined
772 references so that REF disappears from the list of those links."
773 (with-current-buffer buffer
774 (when (not (eq major-mode 'markdown-mode))
775 (error "Not available in current mdoe"))
776 (goto-char (point-max))
777 (indent-new-comment-line)
778 (insert (concat ref ": ")))
779 (switch-to-buffer-other-window buffer)
780 (goto-char (point-max))
781 (when recheck
782 (markdown-check-refs t)))
784 ;; Button which adds an empty Markdown reference definition to the end
785 ;; of buffer specified as its 'target-buffer property. Reference name
786 ;; is button's label
787 (when (>= emacs-major-version 22)
788 (define-button-type 'markdown-ref-button
789 'help-echo "Push to create an empty reference definition"
790 'face 'bold
791 'action (lambda (b)
792 (markdown-add-missing-ref-definition
793 (button-label b) (button-get b 'target-buffer) t))))
795 ;; Button jumping to line in buffer specified as its 'target-buffer
796 ;; property. Line number is button's 'line property.
797 (when (>= emacs-major-version 22)
798 (define-button-type 'goto-line-button
799 'help-echo "Push to go to this line"
800 'face 'italic
801 'action (lambda (b)
802 (message (button-get b 'buffer))
803 (switch-to-buffer-other-window (button-get b 'target-buffer))
804 (goto-line (button-get b 'target-line)))))
806 (defun markdown-check-refs (&optional silent)
807 "Show all undefined Markdown references in current `markdown-mode' buffer.
809 If SILENT is non-nil, do not message anything when no undefined
810 references found.
812 Links which have empty reference definitions are considered to be
813 defined."
814 (interactive "P")
815 (when (not (eq major-mode 'markdown-mode))
816 (error "Not available in current mode"))
817 (let ((oldbuf (current-buffer))
818 (refs (markdown-get-undefined-refs))
819 (refbuf (get-buffer-create (replace-regexp-in-string
820 "%BUFFER%" (buffer-name)
821 markdown-refcheck-buffer t))))
822 (if (null refs)
823 (progn
824 (when (not silent)
825 (message "No undefined references found"))
826 (kill-buffer refbuf))
827 (with-current-buffer refbuf
828 (when view-mode
829 (View-exit-and-edit))
830 (erase-buffer)
831 (insert "Following references lack definitions:")
832 (newline 2)
833 (dolist (ref refs)
834 (let ((button-label (format "%s" (car ref))))
835 (if (>= emacs-major-version 22)
836 ;; Create a reference button in Emacs 22
837 (insert-text-button button-label
838 :type 'markdown-ref-button
839 'target-buffer oldbuf)
840 ;; Insert reference as text in Emacs < 22
841 (insert button-label)))
842 (insert " (")
843 (dolist (occurency (cdr ref))
844 (let ((line (cdr occurency)))
845 (if (>= emacs-major-version 22)
846 ;; Create a line number button in Emacs 22
847 (insert-button (number-to-string line)
848 :type 'goto-line-button
849 'target-buffer oldbuf
850 'target-line line)
851 ;; Insert line number as text in Emacs < 22
852 (insert (number-to-string line)))
853 (insert " "))) (delete-backward-char 1)
854 (insert ")")
855 (newline))
856 (view-buffer-other-window refbuf)
857 (goto-line 4)))))
860 ;;; Outline ===================================================================
862 ;; The following visibility cycling code was taken from org-mode
863 ;; by Carsten Dominik and adapted for markdown-mode.
865 (defvar markdown-cycle-global-status 1)
866 (defvar markdown-cycle-subtree-status nil)
868 ;; Based on org-end-of-subtree from org.el
869 (defun markdown-end-of-subtree (&optional invisible-OK)
870 ;; This is an exact copy of the original function, but it uses
871 ;; `outline-back-to-heading', to make it work also in invisible
872 ;; trees. And is uses an invisible-OK argument.
873 ;; Under Emacs this is not needed, but the old outline.el needs this fix.
874 (outline-back-to-heading invisible-OK)
875 (let ((first t)
876 (level (funcall outline-level)))
877 (while (and (not (eobp))
878 (or first (> (funcall outline-level) level)))
879 (setq first nil)
880 (outline-next-heading))
881 (if (memq (preceding-char) '(?\n ?\^M))
882 (progn
883 ;; Go to end of line before heading
884 (forward-char -1)
885 (if (memq (preceding-char) '(?\n ?\^M))
886 ;; leave blank line before heading
887 (forward-char -1)))))
888 (point))
890 ;; Based on org-cycle from org.el.
891 (defun markdown-cycle (&optional arg)
892 "Visibility cycling for Markdown mode."
893 (interactive "P")
894 (cond
895 ((eq arg t) ;; Global cycling
896 (cond
897 ((and (eq last-command this-command)
898 (eq markdown-cycle-global-status 2))
899 ;; Move from overview to contents
900 (hide-sublevels 1)
901 (message "CONTENTS")
902 (setq markdown-cycle-global-status 3))
904 ((and (eq last-command this-command)
905 (eq markdown-cycle-global-status 3))
906 ;; Move from contents to all
907 (show-all)
908 (message "SHOW ALL")
909 (setq markdown-cycle-global-status 1))
912 ;; Defaults to overview
913 (hide-body)
914 (message "OVERVIEW")
915 (setq markdown-cycle-global-status 2))))
917 ((save-excursion (beginning-of-line 1) (looking-at outline-regexp))
918 ;; At a heading: rotate between three different views
919 (outline-back-to-heading)
920 (let ((goal-column 0) eoh eol eos)
921 ;; Determine boundaries
922 (save-excursion
923 (outline-back-to-heading)
924 (save-excursion
925 (beginning-of-line 2)
926 (while (and (not (eobp)) ;; this is like `next-line'
927 (get-char-property (1- (point)) 'invisible))
928 (beginning-of-line 2)) (setq eol (point)))
929 (outline-end-of-heading) (setq eoh (point))
930 (markdown-end-of-subtree t)
931 (skip-chars-forward " \t\n")
932 (beginning-of-line 1) ; in case this is an item
933 (setq eos (1- (point))))
934 ;; Find out what to do next and set `this-command'
935 (cond
936 ((= eos eoh)
937 ;; Nothing is hidden behind this heading
938 (message "EMPTY ENTRY")
939 (setq markdown-cycle-subtree-status nil))
940 ((>= eol eos)
941 ;; Entire subtree is hidden in one line: open it
942 (show-entry)
943 (show-children)
944 (message "CHILDREN")
945 (setq markdown-cycle-subtree-status 'children))
946 ((and (eq last-command this-command)
947 (eq markdown-cycle-subtree-status 'children))
948 ;; We just showed the children, now show everything.
949 (show-subtree)
950 (message "SUBTREE")
951 (setq markdown-cycle-subtree-status 'subtree))
953 ;; Default action: hide the subtree.
954 (hide-subtree)
955 (message "FOLDED")
956 (setq markdown-cycle-subtree-status 'folded)))))
959 (message "TAB")
960 (indent-relative))))
962 ;; Based on org-shifttab from org.el.
963 (defun markdown-shifttab (&optional arg)
964 "Global visibility cycling or move to previous table field.
965 Calls `markdown-cycle' with argument t"
966 (interactive "P")
967 (markdown-cycle t))
969 ;;; Commands ==================================================================
971 (defun markdown ()
972 "Run markdown on the current buffer and preview the output in another buffer."
973 (interactive)
974 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
975 (shell-command-on-region (region-beginning) (region-end) markdown-command
976 "*markdown-output*" nil)
977 (shell-command-on-region (point-min) (point-max) markdown-command
978 "*markdown-output*" nil)))
980 (defun markdown-preview ()
981 "Run markdown on the current buffer and preview the output in a browser."
982 (interactive)
983 (markdown)
984 (browse-url-of-buffer "*markdown-output*"))
987 ;;; Miscellaneous =============================================================
989 (defun markdown-line-number-at-pos (&optional pos)
990 "Return (narrowed) buffer line number at position POS.
991 If POS is nil, use current buffer location.
992 This is an exact copy of line-number-at-pos for use in emacs21."
993 (let ((opoint (or pos (point))) start)
994 (save-excursion
995 (goto-char (point-min))
996 (setq start (point))
997 (goto-char opoint)
998 (forward-line 0)
999 (1+ (count-lines start (point))))))
1003 ;;; Mode definition ==========================================================
1005 (defun markdown-show-version ()
1006 "Show the version number in the minibuffer."
1007 (interactive)
1008 (message "markdown-mode, version %s" markdown-mode-version))
1010 (define-derived-mode markdown-mode text-mode "Markdown"
1011 "Major mode for editing Markdown files."
1012 ;; Font lock.
1013 (set (make-local-variable 'font-lock-defaults)
1014 '(markdown-mode-font-lock-keywords))
1015 (set (make-local-variable 'font-lock-multiline) t)
1016 ;; For menu support in XEmacs
1017 (easy-menu-add markdown-mode-menu markdown-mode-map)
1018 ;; Outline mode
1019 (make-local-variable 'outline-regexp)
1020 (setq outline-regexp "#+")
1021 ;; Cause use of ellipses for invisible text.
1022 (add-to-invisibility-spec '(outline . t)))
1024 ;(add-to-list 'auto-mode-alist '("\\.text$" . markdown-mode))
1026 (provide 'markdown-mode)
1028 ;;; markdown-mode.el ends here