1 ;;; markdown-mode.el --- Major mode to edit Markdown files in Emacs
3 ;; Copyright (C) 2007-2008 Jason Blevins
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)
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.
28 ;; markdown-mode is a major mode for editing [Markdown][]-formatted
29 ;; text files in GNU Emacs. markdown-mode is free software, licensed
32 ;; [Markdown]: http://daringfireball.net/projects/markdown/
34 ;; The latest version is markdown-mode 1.5, released on October 11, 2007:
36 ;; * [markdown-mode.el][]
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/20071011-001.png
45 ;; [release notes]: http://jblevins.org/projects/markdown-mode/rev-1-5
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.
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.
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
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. Selecting a reference from
92 ;; this list and pressing `RET` will insert a reference template at
93 ;; the end of the buffer.
95 ;; * Images: `C-c C-i`
97 ;; `C-c C-i i` inserts an image, using the active region (if any) as
100 ;; * Physical styles: `C-c C-p`
102 ;; These commands all act on text in the active region, if any, and
103 ;; insert empty markup fragments otherwise. `C-c C-p b` makes the
104 ;; selected text bold, `C-c C-p f` formats the region as fixed-width
105 ;; text, and `C-c C-p i` is used for italic text.
107 ;; * Logical styles: `C-c C-s`
109 ;; These commands all act on text in the active region, if any, and
110 ;; insert empty markup fragments otherwise. Logical styles include
111 ;; blockquote (`C-c C-s b`), preformatted (`C-c C-s p`), code (`C-c C-s c`),
112 ;; emphasis (`C-c C-s e`), and strong (`C-c C-s s`).
114 ;; * Headers: `C-c C-t`
116 ;; All header commands use text in the active region, if any, as the
117 ;; header text. To insert an atx or hash style level-n header, press
118 ;; `C-c C-t n` where n is between 1 and 5. For a top-level setext or
119 ;; underline style header press `C-c C-t t` (mnemonic: title) and for
120 ;; a second-level underline-style header press `C-c C-t s`
121 ;; (mnemonic: section).
125 ;; `C-c -` inserts a horizontal rule.
127 ;; Many of the commands described above behave differently depending on
128 ;; whether Transient Mark mode is enabled or not. When it makes sense,
129 ;; if Transient Mark mode is on and a region is active, the command
130 ;; applies to the text in the region (e.g., `C-c C-p b` makes the region
131 ;; bold). For users who prefer to work outside of Transient Mark mode,
132 ;; in Emacs 22 it can be enabled temporarily by pressing `C-SPC C-SPC`.
134 ;; When applicable, commands that specifically act on the region even
135 ;; outside of Transient Mark mode have the same keybinding as the with
136 ;; the exception of an additional `C-` prefix. For example,
137 ;; `markdown-insert-blockquote` is bound to `C-c C-s b` and only acts on
138 ;; the region in Transient Mark mode while `markdown-blockquote-region`
139 ;; is bound to `C-c C-s C-b` and always applies to the region (when
144 ;; Besides supporting the basic Markdown syntax, markdown-mode also
145 ;; includes syntax highlighting for `[[Wiki Links]]` by default.
146 ;; Syntax highlighting for mathematical expressions written in LaTeX
147 ;; (only expressions denoted by `$..$`, `$$..$$`, or `\[..\]`) can be
148 ;; enabled by editing `markdown-mode.el` and changing
149 ;; `(defvar markdown-enable-itex nil)` to `(defvar markdown-enable-itex t)`.
153 ;; * Cyril Brulebois <cyril.brulebois@enst-bretagne.fr> for Debian packaging.
154 ;; * Conal Elliott <conal@conal.net> for a font-lock regexp patch.
155 ;; * Edward O'Connor <hober0@gmail.com> for a font-lock regexp fix.
156 ;; * Greg Bognar <greg_bognar@hms.harvard.edu> for menus and a patch.
157 ;; * Daniel Burrows <dburrows@debian.org> for filing Debian bug #456592.
158 ;; * Peter S. Galbraith <psg@debian.org> for maintaining emacs-goodies-el.
159 ;; * Dmitry Dzhus <mail@sphinx.net.ru> for reference checking functions.
163 ;; This mode has only been tested on Emacs 21.4 and 22.0. Please let me
164 ;; know if there are problems on other versions. If you find any bugs,
165 ;; such as syntax highlighting issues, please construct a test case and
166 ;; email me at <jrblevin@sdf.lonestar.org>.
174 ;;; User Customizable Variables ===============================================
176 ;; To enable LaTeX/itex syntax highlighting, change to
177 ;; (defvar markdown-enable-itex t)
178 (defvar markdown-enable-itex nil
)
181 ;;; Customizable variables ====================================================
184 (defconst markdown-mode-version
"1.6-dev")
186 ;; A hook for users to run their own code when the mode is loaded.
187 (defvar markdown-mode-hook nil
)
190 ;;; Customizable variables ====================================================
192 (defgroup markdown nil
193 "Major mode for editing text files in Markdown format."
196 :link
'(url-link "http://jblevins.org/projects/markdown-mode/"))
198 (defcustom markdown-command
"markdown"
199 "Command to run markdown."
203 (defcustom markdown-hr-length
5
204 "Length of horizonal rules."
208 (defcustom markdown-bold-underscore nil
209 "Use two underscores for bold instead of two asterisks."
213 (defcustom markdown-italic-underscore nil
214 "Use underscores for italic instead of asterisks."
219 ;;; Font lock =================================================================
223 (defgroup markdown-faces nil
224 "Faces used in Markdown Mode"
228 (defcustom markdown-italic-face
'font-lock-variable-name-face
230 :group
'markdown-faces
233 (defcustom markdown-bold-face
'font-lock-type-face
235 :group
'markdown-faces
238 (defcustom markdown-header-face
'font-lock-function-name-face
240 :group
'markdown-faces
243 (defcustom markdown-inline-code-face
'font-lock-builtin-face
245 :group
'markdown-faces
248 (defcustom markdown-list-face
'font-lock-variable-name-face
250 :group
'markdown-faces
253 (defcustom markdown-blockquote-face
'font-lock-comment-face
254 "Blockquote sections and preformatted text"
255 :group
'markdown-faces
258 (defcustom markdown-link-face
'font-lock-constant-face
260 :group
'markdown-faces
263 (defcustom markdown-reference-face
'font-lock-type-face
265 :group
'markdown-faces
268 (defcustom markdown-url-face
'font-lock-string-face
270 :group
'markdown-faces
273 (defcustom markdown-math-face
'font-lock-builtin-face
275 :group
'markdown-faces
278 (defconst markdown-regex-link-inline
279 "\\(!?\\[[^]]*?\\]\\)\\(([^\\)]*)\\)"
280 "Regular expression for a [text](file) or an image link ![text](file)")
282 (defconst markdown-regex-link-reference
283 "\\(!?\\[[^]]+?\\]\\)[ ]?\\(\\[[^]]*?\\]\\)"
284 "Regular expression for a reference link [text][id]")
286 (defconst markdown-regex-reference-definition
287 "^ \\{0,3\\}\\(\\[.+?\\]\\): [ ]?\\(.*?\\)\\(\"[^\"]+?\"\\)?$"
288 "Regular expression for a link definition [id]: ...")
290 (defconst markdown-regex-header-atx
291 "^\\(#+ \\)\\(.*?\\)\\($\\| #+$\\)"
292 "Regular expression for atx-style (hash mark) headers")
294 (defconst markdown-regex-header-setext
295 "^\\(.*\\)\n\\(===+\\|---+\\)$"
296 "Regular expression for setext-style (underline) headers")
298 (defconst markdown-regex-hr
299 "^\\(\\*[ ]?\\*[ ]?\\*[ ]?[\\* ]*\\|-[ ]?-[ ]?-[--- ]*\\)$"
300 "Regular expression for matching Markdown horizontal rules")
302 (defconst markdown-regex-code
303 "\\(^\\|[^\\]\\)\\(\\(`\\{1,2\\}\\)\\([^ \\]\\|[^ ].*?[^ \\]\\)\\3\\)"
304 "Regular expression for matching inline code fragments")
306 (defconst markdown-regex-pre
308 "Regular expression for matching preformatted text sections")
310 (defconst markdown-regex-list
311 "^[ \t]*\\([0-9]+\\.\\|[\\*\\+-]\\) "
312 "Regular expression for matching list markers")
314 (defconst markdown-regex-bold
315 "\\(^\\|[^\\]\\)\\(\\([*_]\\{2\\}\\)\\(.\\|\n\\)*?[^\\ ]\\3\\)"
316 "Regular expression for matching bold text")
318 (defconst markdown-regex-italic
319 "\\(^\\|[^\\]\\)\\(\\([*_]\\)\\([^ \\]\\3\\|[^ ]\\(.\\|\n\\)*?[^\\ ]\\3\\)\\)"
320 "Regular expression for matching italic text")
322 (defconst markdown-regex-blockquote
324 "Regular expression for matching blockquote lines")
326 (defconst markdown-regex-line-break
328 "Regular expression for matching line breaks")
330 (defconst markdown-regex-wiki-link
332 "Regular expression for matching wiki links")
334 (defconst markdown-regex-uri
335 "<\\(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\\)://[^>]*>"
336 "Regular expression for matching inline URIs")
338 (defconst markdown-regex-email
339 "<\\(\\sw\\|\\s_\\|\\s.\\)+@\\(\\sw\\|\\s_\\|\\s.\\)+>"
340 "Regular expression for matching inline email addresses")
342 (defconst markdown-regex-latex-expression
343 "\\(^\\|[^\\]\\)\\(\\$\\($\\([^\\$]\\|\\\\.\\)*\\$\\|\\([^\\$]\\|\\\\.\\)*\\)\\$\\)"
344 "Regular expression for itex $..$ or $$..$$ math mode expressions")
346 (defconst markdown-regex-latex-display
347 "^\\\\\\[\\(.\\|\n\\)*?\\\\\\]$"
348 "Regular expression for itex \[..\] display mode expressions")
350 (defconst markdown-mode-font-lock-keywords-basic
352 (cons markdown-regex-code markdown-inline-code-face
)
353 (cons markdown-regex-pre markdown-blockquote-face
)
354 (cons markdown-regex-header-setext markdown-header-face
)
355 (cons markdown-regex-header-atx markdown-header-face
)
356 (cons markdown-regex-list markdown-list-face
)
357 (cons markdown-regex-hr markdown-header-face
)
358 (cons markdown-regex-link-inline
359 '((1 markdown-link-face t
)
360 (2 markdown-url-face t
)))
361 (cons markdown-regex-link-reference
362 '((1 markdown-link-face t
)
363 (2 markdown-reference-face t
)))
364 (cons markdown-regex-reference-definition
365 '((1 markdown-reference-face t
)
366 (2 markdown-url-face t
)
367 (3 markdown-link-face t
)))
368 (cons markdown-regex-bold
'(2 markdown-bold-face
))
369 (cons markdown-regex-italic
'(2 markdown-italic-face
))
370 (cons markdown-regex-blockquote markdown-blockquote-face
)
371 (cons markdown-regex-wiki-link markdown-link-face
)
372 (cons markdown-regex-uri markdown-link-face
)
373 (cons markdown-regex-email markdown-link-face
))
374 "Syntax highlighting for Markdown files.")
377 ;; Includes additional Latex/itex/Instiki font lock keywords
378 (defconst markdown-mode-font-lock-keywords-itex
381 ;; itex math mode $..$ or $$..$$
382 (cons markdown-regex-latex-expression
'(2 markdown-math-face
))
383 ;; Display mode equations with brackets: \[ \]
384 (cons markdown-regex-latex-display markdown-math-face
)
385 ;; Equation reference (eq:foo)
386 (cons "(eq:\\w+)" markdown-reference-face
)
387 ;; Equation reference \eqref
388 (cons "\\\\eqref{\\w+}" markdown-reference-face
))
389 markdown-mode-font-lock-keywords-basic
)
390 "Syntax highlighting for Markdown, itex, and wiki expressions.")
393 (defvar markdown-mode-font-lock-keywords
394 (if markdown-enable-itex
395 markdown-mode-font-lock-keywords-itex
396 markdown-mode-font-lock-keywords-basic
)
397 "Default highlighting expressions for Markdown mode")
401 ;;; Syntax Table ==============================================================
403 (defvar markdown-mode-syntax-table
404 (let ((markdown-mode-syntax-table (make-syntax-table)))
405 (modify-syntax-entry ?
\" "w" markdown-mode-syntax-table
)
406 markdown-mode-syntax-table
)
407 "Syntax table for markdown-mode")
411 ;;; Element Insertion =========================================================
413 (defun markdown-wrap-or-insert (s1 s2
)
414 "Insert the strings S1 and S2.
415 If Transient Mark mode is on and a region is active, wrap the strings S1
416 and S2 around the region."
417 (if (and transient-mark-mode mark-active
)
418 (let ((a (region-beginning)) (b (region-end)))
421 (goto-char (+ b
(length s1
)))
425 (defun markdown-insert-hr ()
426 "Inserts a horizonal rule."
429 (dotimes (count (- markdown-hr-length
1) hr
) ; Count to n - 1
430 (setq hr
(concat "* " hr
))) ; Build HR string
431 (setq hr
(concat hr
"*\n")) ; Add the n-th *
434 (defun markdown-insert-bold ()
435 "Inserts markup for a bold word or phrase.
436 If Transient Mark mode is on and a region is active, it is made bold."
438 (if markdown-bold-underscore
439 (markdown-wrap-or-insert "__" "__")
440 (markdown-wrap-or-insert "**" "**"))
443 (defun markdown-insert-italic ()
444 "Inserts markup for an italic word or phrase.
445 If Transient Mark mode is on and a region is active, it is made italic."
447 (if markdown-italic-underscore
448 (markdown-wrap-or-insert "_" "_")
449 (markdown-wrap-or-insert "*" "*"))
452 (defun markdown-insert-code ()
453 "Inserts markup for an inline code fragment.
454 If Transient Mark mode is on and a region is active, it is marked
457 (markdown-wrap-or-insert "`" "`")
460 (defun markdown-insert-link ()
461 "Inserts an inline link of the form []().
462 If Transient Mark mode is on and a region is active, it is used
465 (markdown-wrap-or-insert "[" "]")
469 (defun markdown-insert-wiki-link ()
470 "Inserts a wiki link of the form [[WikiLink]].
471 If Transient Mark mode is on and a region is active, it is used
474 (markdown-wrap-or-insert "[[" "]]")
477 (defun markdown-insert-image ()
478 "Inserts an inline image tag of the form ![]().
479 If Transient Mark mode is on and a region is active, it is used
480 as the alt text of the image."
482 (markdown-wrap-or-insert "![" "]")
486 (defun markdown-insert-header-1 ()
487 "Inserts a first level atx-style (hash mark) header.
488 If Transient Mark mode is on and a region is active, it is used
491 (markdown-insert-header 1))
493 (defun markdown-insert-header-2 ()
494 "Inserts a second level atx-style (hash mark) header.
495 If Transient Mark mode is on and a region is active, it is used
498 (markdown-insert-header 2))
500 (defun markdown-insert-header-3 ()
501 "Inserts a third level atx-style (hash mark) header.
502 If Transient Mark mode is on and a region is active, it is used
505 (markdown-insert-header 3))
507 (defun markdown-insert-header-4 ()
508 "Inserts a fourth level atx-style (hash mark) header.
509 If Transient Mark mode is on and a region is active, it is used
512 (markdown-insert-header 4))
514 (defun markdown-insert-header-5 ()
515 "Inserts a fifth level atx-style (hash mark) header.
516 If Transient Mark mode is on and a region is active, it is used
519 (markdown-insert-header 5))
521 (defun markdown-insert-header (n)
522 "Inserts an atx-style (hash mark) header.
523 With no prefix argument, insert a level-1 header. With prefix N,
524 insert a level-N header. If Transient Mark mode is on and the
525 region is active, it is used as the header text."
527 (unless n
; Test to see if n is defined
528 (setq n
1)) ; Default to level 1 header
530 (dotimes (count n hdr
)
531 (setq hdr
(concat "#" hdr
))) ; Build a hash mark header string
532 (setq hdrl
(concat hdr
" "))
533 (setq hdrr
(concat " " hdr
))
534 (markdown-wrap-or-insert hdrl hdrr
))
535 (backward-char (+ 1 n
)))
537 (defun markdown-insert-title ()
538 "Insert a setext-style (underline) first level header.
539 If Transient Mark mode is on and a region is active, it is used
542 (if (and transient-mark-mode mark-active
)
543 (let ((a (region-beginning))
548 (dotimes (count len hdr
)
549 (setq hdr
(concat "=" hdr
))) ; Build a === title underline
551 (insert "\n" hdr
"\n"))
552 (insert "\n==========\n")
555 (defun markdown-insert-section ()
556 "Insert a setext-style (underline) second level header.
557 If Transient Mark mode is on and a region is active, it is used
560 (if (and transient-mark-mode mark-active
)
561 (let ((a (region-beginning))
566 (dotimes (count len hdr
)
567 (setq hdr
(concat "-" hdr
))) ; Build a --- section underline
569 (insert "\n" hdr
"\n"))
570 (insert "\n----------\n")
573 (defun markdown-insert-blockquote ()
574 "Start a blockquote section (or blockquote the region).
575 If Transient Mark mode is on and a region is active, it is used as
576 the blockquote text."
578 (if (and (boundp 'transient-mark-mode
) transient-mark-mode mark-active
)
579 (markdown-blockquote-region)
582 (defun markdown-blockquote-region (beg end
&optional arg
)
583 "Blockquote the region."
584 (interactive "*r\nP")
586 (perform-replace "^" "> " nil
1 nil nil nil beg end
)))
588 (defun markdown-insert-pre ()
589 "Start a preformatted section (or apply to the region).
590 If Transient Mark mode is on and a region is active, it is marked
591 as preformatted text."
593 (if (and (boundp 'transient-mark-mode
) transient-mark-mode mark-active
)
594 (markdown-pre-region)
597 (defun markdown-pre-region (beg end
&optional arg
)
598 "Format the region as preformatted text."
599 (interactive "*r\nP")
601 (perform-replace "^" " " nil
1 nil nil nil beg end
)))
606 ;;; Keymap ====================================================================
608 (defvar markdown-mode-map
609 (let ((markdown-mode-map (make-keymap)))
611 (define-key markdown-mode-map
"\C-c\C-al" 'markdown-insert-link
)
612 (define-key markdown-mode-map
"\C-c\C-aw" 'markdown-insert-wiki-link
)
613 (define-key markdown-mode-map
"\C-c\C-ii" 'markdown-insert-image
)
614 (define-key markdown-mode-map
"\C-c\C-t1" 'markdown-insert-header-1
)
615 (define-key markdown-mode-map
"\C-c\C-t2" 'markdown-insert-header-2
)
616 (define-key markdown-mode-map
"\C-c\C-t3" 'markdown-insert-header-3
)
617 (define-key markdown-mode-map
"\C-c\C-t4" 'markdown-insert-header-4
)
618 (define-key markdown-mode-map
"\C-c\C-t5" 'markdown-insert-header-5
)
619 (define-key markdown-mode-map
"\C-c\C-pb" 'markdown-insert-bold
)
620 (define-key markdown-mode-map
"\C-c\C-ss" 'markdown-insert-bold
)
621 (define-key markdown-mode-map
"\C-c\C-pi" 'markdown-insert-italic
)
622 (define-key markdown-mode-map
"\C-c\C-se" 'markdown-insert-italic
)
623 (define-key markdown-mode-map
"\C-c\C-pf" 'markdown-insert-code
)
624 (define-key markdown-mode-map
"\C-c\C-sc" 'markdown-insert-code
)
625 (define-key markdown-mode-map
"\C-c\C-sb" 'markdown-insert-blockquote
)
626 (define-key markdown-mode-map
"\C-c\C-s\C-b" 'markdown-blockquote-region
)
627 (define-key markdown-mode-map
"\C-c\C-sp" 'markdown-insert-pre
)
628 (define-key markdown-mode-map
"\C-c\C-s\C-p" 'markdown-pre-region
)
629 (define-key markdown-mode-map
"\C-c-" 'markdown-insert-hr
)
630 (define-key markdown-mode-map
"\C-c\C-tt" 'markdown-insert-title
)
631 (define-key markdown-mode-map
"\C-c\C-ts" 'markdown-insert-section
)
632 ;; Markdown functions
633 (define-key markdown-mode-map
"\C-c\C-cm" 'markdown
)
634 (define-key markdown-mode-map
"\C-c\C-cp" 'markdown-preview
)
636 (define-key markdown-mode-map
"\C-c\C-cc" 'markdown-check-refs
)
638 "Keymap for Markdown major mode")
640 ;;; Menu ==================================================================
642 (easy-menu-define markdown-mode-menu markdown-mode-map
643 "Menu for Markdown mode"
646 ["Preview" markdown-preview
]
649 ["Insert Title" markdown-insert-title
]
650 ["Insert Section" markdown-insert-section
])
652 ["First level" markdown-insert-header-1
]
653 ["Second level" markdown-insert-header-2
]
654 ["Third level" markdown-insert-header-3
]
655 ["Fourth level" markdown-insert-header-4
]
656 ["Fifth level" markdown-insert-header-5
])
658 ["Bold" markdown-insert-bold
]
659 ["Italic" markdown-insert-italic
]
660 ["Blockquote" markdown-insert-blockquote
]
661 ["Preformatted" markdown-insert-pre
]
662 ["Code" markdown-insert-code
]
664 ["Insert inline link" markdown-insert-link
]
665 ["Insert image" markdown-insert-image
]
666 ["Insert horizontal rule" markdown-insert-hr
]
668 ["Check references" markdown-check-refs
]
670 ["Version" markdown-show-version
]
675 ;;; References ================================================================
677 ;;; Undefined reference checking code by Dmitry Dzhus <mail@sphinx.net.ru>.
679 (defconst markdown-refcheck-buffer
680 "*Undefined references for %BUFFER%*"
681 "Name of buffer which will contain a list of undefined
682 references in `markdown-mode' buffer named %BUFFER%.")
684 (defun markdown-has-reference-definition (reference)
685 "Find out whether Markdown REFERENCE is defined.
687 REFERENCE should include the square brackets, like [this]."
688 (let ((reference (downcase reference
)))
690 (goto-char (point-min))
692 (while (re-search-forward markdown-regex-reference-definition nil t
)
693 (when (string= reference
(downcase (match-string-no-properties 1)))
694 (throw 'found t
)))))))
696 (defun markdown-get-undefined-refs ()
697 "Return a list of undefined Markdown references.
699 Result is an alist of pairs (reference . occurencies), where
700 occurencies is itself another alist of pairs (label .
703 For example, an alist corresponding to [Nice editor][Emacs] at line 12,
704 \[GNU Emacs][Emacs] at line 45 and [manual][elisp] at line 127 is
705 \((\"[emacs]\" (\"[Nice editor]\" . 12) (\"[GNU Emacs]\" . 45)) (\"[elisp]\" (\"[manual]\" . 127)))."
708 (goto-char (point-min))
710 (re-search-forward markdown-regex-link-reference nil t
)
711 (let* ((label (match-string-no-properties 1))
712 (reference (match-string-no-properties 2))
713 (target (downcase (if (string= reference
"[]") label reference
))))
714 (unless (markdown-has-reference-definition target
)
715 (let ((entry (assoc target missing
)))
717 (add-to-list 'missing
(cons target
718 (list (cons label
(line-number-at-pos)))) t
)
720 (append (cdr entry
) (list (cons label
(line-number-at-pos))))))))))
723 (defun markdown-add-missing-ref-definition (ref buffer
&optional recheck
)
724 "Add blank REF definition to the end of BUFFER.
726 REF is a Markdown reference in square brackets, like \"[lisp-history]\".
728 When RECHECK is non-nil, BUFFER gets rechecked for undefined
729 references so that REF disappears from the list of those links."
730 (with-current-buffer buffer
731 (when (not (eq major-mode
'markdown-mode
))
732 (error "Not available in current mdoe"))
733 (goto-char (point-max))
734 (indent-new-comment-line)
735 (insert (concat ref
": ")))
736 (switch-to-buffer-other-window buffer
)
737 (goto-char (point-max))
739 (markdown-check-refs t
)))
741 ;; Button which adds an empty Markdown reference definition to the end
742 ;; of buffer specified as its 'target-buffer property. Reference name
744 (define-button-type 'markdown-ref-button
745 'help-echo
"Push to create an empty reference definition"
748 (markdown-add-missing-ref-definition
749 (button-label b
) (button-get b
'target-buffer
) t
)))
751 ;; Button jumping to line in buffer specified as its 'target-buffer
752 ;; property. Line number is button's 'line property.
753 (define-button-type 'goto-line-button
754 'help-echo
"Push to go to this line"
757 (message (button-get b
'buffer
))
758 (switch-to-buffer-other-window (button-get b
'target-buffer
))
759 (goto-line (button-get b
'target-line
))))
761 (defun markdown-check-refs (&optional silent
)
762 "Show all undefined Markdown references in current `markdown-mode' buffer.
764 If SILENT is non-nil, do not message anything when no undefined
767 Links which have empty reference definitions are considered to be
770 (when (not (eq major-mode
'markdown-mode
))
771 (error "Not available in current mode"))
772 (let ((oldbuf (current-buffer))
773 (refs (markdown-get-undefined-refs))
774 (refbuf (get-buffer-create (replace-regexp-in-string
775 "%BUFFER%" (buffer-name)
776 markdown-refcheck-buffer t
))))
780 (message "No undefined references found"))
781 (kill-buffer refbuf
))
782 (with-current-buffer refbuf
784 (View-exit-and-edit))
786 (insert "Following references lack definitions:")
789 (let ((button-label (format "%s" (car ref
))))
790 (insert-text-button button-label
791 :type
'markdown-ref-button
792 'target-buffer oldbuf
)
794 (dolist (occurency (cdr ref
))
795 (let ((line (cdr occurency
)))
796 (insert-button (number-to-string line
)
797 :type
'goto-line-button
798 'target-buffer oldbuf
800 (insert " "))) (delete-backward-char 1)
803 (view-buffer-other-window refbuf
)
807 ;;; Commands ==================================================================
810 "Run markdown on the current buffer and preview the output in another buffer."
812 (if (and (boundp 'transient-mark-mode
) transient-mark-mode mark-active
)
813 (shell-command-on-region (region-beginning) (region-end) markdown-command
814 "*markdown-output*" nil
)
815 (shell-command-on-region (point-min) (point-max) markdown-command
816 "*markdown-output*" nil
)))
818 (defun markdown-preview ()
819 "Run markdown on the current buffer and preview the output in a browser."
822 (browse-url-of-buffer "*markdown-output*"))
826 ;;; Mode definition ==========================================================
828 (defun markdown-show-version ()
829 "Show the version number in the minibuffer."
831 (message "markdown-mode, version %s" markdown-mode-version
))
833 (define-derived-mode markdown-mode text-mode
"Markdown"
834 "Major mode for editing Markdown files."
836 (set (make-local-variable 'font-lock-defaults
)
837 '(markdown-mode-font-lock-keywords))
838 (set (make-local-variable 'font-lock-multiline
) t
)
839 ;; For menu support in XEmacs
840 (easy-menu-add markdown-mode-menu markdown-mode-map
))
842 ;(add-to-list 'auto-mode-alist '("\\.text$" . markdown-mode))
844 (provide 'markdown-mode
)
846 ;;; markdown-mode.el ends here