Support reference checking in Emacs 21
[markdown-mode/intrigeri.git] / markdown-mode.el
blobdfd50c7c3baeabcc1c96007f1fcf23551f9f71a9
1 ;;; markdown-mode.el --- Major mode to edit Markdown files in Emacs
3 ;; Copyright (C) 2007-2008 Jason Blevins
5 ;; Version: 1.6-dev
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.5, released on October 11, 2007:
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/20071011-001.png
45 ;; [release notes]: http://jblevins.org/projects/markdown-mode/rev-1-5
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 ;;; Extensions:
146 ;; Besides supporting the basic Markdown syntax, markdown-mode also
147 ;; includes syntax highlighting for `[[Wiki Links]]` by default.
148 ;; Syntax highlighting for mathematical expressions written in LaTeX
149 ;; (only expressions denoted by `$..$`, `$$..$$`, or `\[..\]`) can be
150 ;; enabled by editing `markdown-mode.el` and changing
151 ;; `(defvar markdown-enable-itex nil)` to `(defvar markdown-enable-itex t)`.
153 ;;; Thanks:
155 ;; * Cyril Brulebois <cyril.brulebois@enst-bretagne.fr> for Debian packaging.
156 ;; * Conal Elliott <conal@conal.net> for a font-lock regexp patch.
157 ;; * Edward O'Connor <hober0@gmail.com> for a font-lock regexp fix.
158 ;; * Greg Bognar <greg_bognar@hms.harvard.edu> for menus and a patch.
159 ;; * Daniel Burrows <dburrows@debian.org> for filing Debian bug #456592.
160 ;; * Peter S. Galbraith <psg@debian.org> for maintaining emacs-goodies-el.
161 ;; * Dmitry Dzhus <mail@sphinx.net.ru> for reference checking functions.
163 ;;; Bugs:
165 ;; This mode has only been tested on Emacs 21.4 and 22.0. Please let me
166 ;; know if there are problems on other versions. If you find any bugs,
167 ;; such as syntax highlighting issues, please construct a test case and
168 ;; email me at <jrblevin@sdf.lonestar.org>.
172 ;;; Code:
174 (require 'easymenu)
176 ;;; User Customizable Variables ===============================================
178 ;; To enable LaTeX/itex syntax highlighting, change to
179 ;; (defvar markdown-enable-itex t)
180 (defvar markdown-enable-itex nil)
183 ;;; Customizable variables ====================================================
185 ;; Current revision
186 (defconst markdown-mode-version "1.6-dev")
188 ;; A hook for users to run their own code when the mode is loaded.
189 (defvar markdown-mode-hook nil)
192 ;;; Customizable variables ====================================================
194 (defgroup markdown nil
195 "Major mode for editing text files in Markdown format."
196 :prefix "markdown-"
197 :group 'wp
198 :link '(url-link "http://jblevins.org/projects/markdown-mode/"))
200 (defcustom markdown-command "markdown"
201 "Command to run markdown."
202 :group 'markdown
203 :type 'string)
205 (defcustom markdown-hr-length 5
206 "Length of horizonal rules."
207 :group 'markdown
208 :type 'integer)
210 (defcustom markdown-bold-underscore nil
211 "Use two underscores for bold instead of two asterisks."
212 :group 'markdown
213 :type 'boolean)
215 (defcustom markdown-italic-underscore nil
216 "Use underscores for italic instead of asterisks."
217 :group 'markdown
218 :type 'boolean)
221 ;;; Font lock =================================================================
223 (require 'font-lock)
225 (defgroup markdown-faces nil
226 "Faces used in Markdown Mode"
227 :group 'markdown
228 :group 'faces)
230 (defcustom markdown-italic-face 'font-lock-variable-name-face
231 "Italic text."
232 :group 'markdown-faces
233 :type '(face))
235 (defcustom markdown-bold-face 'font-lock-type-face
236 "Bold text"
237 :group 'markdown-faces
238 :type '(face))
240 (defcustom markdown-header-face 'font-lock-function-name-face
241 "Headers"
242 :group 'markdown-faces
243 :type '(face))
245 (defcustom markdown-inline-code-face 'font-lock-builtin-face
246 "Inline code"
247 :group 'markdown-faces
248 :type '(face))
250 (defcustom markdown-list-face 'font-lock-variable-name-face
251 "List item markers"
252 :group 'markdown-faces
253 :type '(face))
255 (defcustom markdown-blockquote-face 'font-lock-comment-face
256 "Blockquote sections and preformatted text"
257 :group 'markdown-faces
258 :type '(face))
260 (defcustom markdown-link-face 'font-lock-constant-face
261 "Link text"
262 :group 'markdown-faces
263 :type '(face))
265 (defcustom markdown-reference-face 'font-lock-type-face
266 "Link references"
267 :group 'markdown-faces
268 :type '(face))
270 (defcustom markdown-url-face 'font-lock-string-face
271 "URLs"
272 :group 'markdown-faces
273 :type '(face))
275 (defcustom markdown-math-face 'font-lock-builtin-face
276 "LaTeX expressions"
277 :group 'markdown-faces
278 :type '(face))
280 (defconst markdown-regex-link-inline
281 "\\(!?\\[[^]]*?\\]\\)\\(([^\\)]*)\\)"
282 "Regular expression for a [text](file) or an image link ![text](file)")
284 (defconst markdown-regex-link-reference
285 "\\(!?\\[[^]]+?\\]\\)[ ]?\\(\\[[^]]*?\\]\\)"
286 "Regular expression for a reference link [text][id]")
288 (defconst markdown-regex-reference-definition
289 "^ \\{0,3\\}\\(\\[.+?\\]\\): [ ]?\\(.*?\\)\\(\"[^\"]+?\"\\)?$"
290 "Regular expression for a link definition [id]: ...")
292 (defconst markdown-regex-header-atx
293 "^\\(#+ \\)\\(.*?\\)\\($\\| #+$\\)"
294 "Regular expression for atx-style (hash mark) headers")
296 (defconst markdown-regex-header-setext
297 "^\\(.*\\)\n\\(===+\\|---+\\)$"
298 "Regular expression for setext-style (underline) headers")
300 (defconst markdown-regex-hr
301 "^\\(\\*[ ]?\\*[ ]?\\*[ ]?[\\* ]*\\|-[ ]?-[ ]?-[--- ]*\\)$"
302 "Regular expression for matching Markdown horizontal rules")
304 (defconst markdown-regex-code
305 "\\(^\\|[^\\]\\)\\(\\(`\\{1,2\\}\\)\\([^ \\]\\|[^ ].*?[^ \\]\\)\\3\\)"
306 "Regular expression for matching inline code fragments")
308 (defconst markdown-regex-pre
309 "^ .*$"
310 "Regular expression for matching preformatted text sections")
312 (defconst markdown-regex-list
313 "^[ \t]*\\([0-9]+\\.\\|[\\*\\+-]\\) "
314 "Regular expression for matching list markers")
316 (defconst markdown-regex-bold
317 "\\(^\\|[^\\]\\)\\(\\([*_]\\{2\\}\\)\\(.\\|\n\\)*?[^\\ ]\\3\\)"
318 "Regular expression for matching bold text")
320 (defconst markdown-regex-italic
321 "\\(^\\|[^\\]\\)\\(\\([*_]\\)\\([^ \\]\\3\\|[^ ]\\(.\\|\n\\)*?[^\\ ]\\3\\)\\)"
322 "Regular expression for matching italic text")
324 (defconst markdown-regex-blockquote
325 "^>.*$"
326 "Regular expression for matching blockquote lines")
328 (defconst markdown-regex-line-break
329 " $"
330 "Regular expression for matching line breaks")
332 (defconst markdown-regex-wiki-link
333 "\\[\\[[^]]+\\]\\]"
334 "Regular expression for matching wiki links")
336 (defconst markdown-regex-uri
337 "<\\(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\\)://[^>]*>"
338 "Regular expression for matching inline URIs")
340 (defconst markdown-regex-email
341 "<\\(\\sw\\|\\s_\\|\\s.\\)+@\\(\\sw\\|\\s_\\|\\s.\\)+>"
342 "Regular expression for matching inline email addresses")
344 (defconst markdown-regex-latex-expression
345 "\\(^\\|[^\\]\\)\\(\\$\\($\\([^\\$]\\|\\\\.\\)*\\$\\|\\([^\\$]\\|\\\\.\\)*\\)\\$\\)"
346 "Regular expression for itex $..$ or $$..$$ math mode expressions")
348 (defconst markdown-regex-latex-display
349 "^\\\\\\[\\(.\\|\n\\)*?\\\\\\]$"
350 "Regular expression for itex \[..\] display mode expressions")
352 (defconst markdown-mode-font-lock-keywords-basic
353 (list
354 (cons markdown-regex-code markdown-inline-code-face)
355 (cons markdown-regex-pre markdown-blockquote-face)
356 (cons markdown-regex-header-setext markdown-header-face)
357 (cons markdown-regex-header-atx markdown-header-face)
358 (cons markdown-regex-list markdown-list-face)
359 (cons markdown-regex-hr markdown-header-face)
360 (cons markdown-regex-link-inline
361 '((1 markdown-link-face t)
362 (2 markdown-url-face t)))
363 (cons markdown-regex-link-reference
364 '((1 markdown-link-face t)
365 (2 markdown-reference-face t)))
366 (cons markdown-regex-reference-definition
367 '((1 markdown-reference-face t)
368 (2 markdown-url-face t)
369 (3 markdown-link-face t)))
370 (cons markdown-regex-bold '(2 markdown-bold-face))
371 (cons markdown-regex-italic '(2 markdown-italic-face))
372 (cons markdown-regex-blockquote markdown-blockquote-face)
373 (cons markdown-regex-wiki-link markdown-link-face)
374 (cons markdown-regex-uri markdown-link-face)
375 (cons markdown-regex-email markdown-link-face))
376 "Syntax highlighting for Markdown files.")
379 ;; Includes additional Latex/itex/Instiki font lock keywords
380 (defconst markdown-mode-font-lock-keywords-itex
381 (append
382 (list
383 ;; itex math mode $..$ or $$..$$
384 (cons markdown-regex-latex-expression '(2 markdown-math-face))
385 ;; Display mode equations with brackets: \[ \]
386 (cons markdown-regex-latex-display markdown-math-face)
387 ;; Equation reference (eq:foo)
388 (cons "(eq:\\w+)" markdown-reference-face)
389 ;; Equation reference \eqref
390 (cons "\\\\eqref{\\w+}" markdown-reference-face))
391 markdown-mode-font-lock-keywords-basic)
392 "Syntax highlighting for Markdown, itex, and wiki expressions.")
395 (defvar markdown-mode-font-lock-keywords
396 (if markdown-enable-itex
397 markdown-mode-font-lock-keywords-itex
398 markdown-mode-font-lock-keywords-basic)
399 "Default highlighting expressions for Markdown mode")
403 ;;; Syntax Table ==============================================================
405 (defvar markdown-mode-syntax-table
406 (let ((markdown-mode-syntax-table (make-syntax-table)))
407 (modify-syntax-entry ?\" "w" markdown-mode-syntax-table)
408 markdown-mode-syntax-table)
409 "Syntax table for markdown-mode")
413 ;;; Element Insertion =========================================================
415 (defun markdown-wrap-or-insert (s1 s2)
416 "Insert the strings S1 and S2.
417 If Transient Mark mode is on and a region is active, wrap the strings S1
418 and S2 around the region."
419 (if (and transient-mark-mode mark-active)
420 (let ((a (region-beginning)) (b (region-end)))
421 (goto-char a)
422 (insert s1)
423 (goto-char (+ b (length s1)))
424 (insert s2))
425 (insert s1 s2)))
427 (defun markdown-insert-hr ()
428 "Inserts a horizonal rule."
429 (interactive)
430 (let (hr)
431 (dotimes (count (- markdown-hr-length 1) hr) ; Count to n - 1
432 (setq hr (concat "* " hr))) ; Build HR string
433 (setq hr (concat hr "*\n")) ; Add the n-th *
434 (insert hr)))
436 (defun markdown-insert-bold ()
437 "Inserts markup for a bold word or phrase.
438 If Transient Mark mode is on and a region is active, it is made bold."
439 (interactive)
440 (if markdown-bold-underscore
441 (markdown-wrap-or-insert "__" "__")
442 (markdown-wrap-or-insert "**" "**"))
443 (backward-char 2))
445 (defun markdown-insert-italic ()
446 "Inserts markup for an italic word or phrase.
447 If Transient Mark mode is on and a region is active, it is made italic."
448 (interactive)
449 (if markdown-italic-underscore
450 (markdown-wrap-or-insert "_" "_")
451 (markdown-wrap-or-insert "*" "*"))
452 (backward-char 1))
454 (defun markdown-insert-code ()
455 "Inserts markup for an inline code fragment.
456 If Transient Mark mode is on and a region is active, it is marked
457 as inline code."
458 (interactive)
459 (markdown-wrap-or-insert "`" "`")
460 (backward-char 1))
462 (defun markdown-insert-link ()
463 "Inserts an inline link of the form []().
464 If Transient Mark mode is on and a region is active, it is used
465 as the link text."
466 (interactive)
467 (markdown-wrap-or-insert "[" "]")
468 (insert "()")
469 (backward-char 1))
471 (defun markdown-insert-wiki-link ()
472 "Inserts a wiki link of the form [[WikiLink]].
473 If Transient Mark mode is on and a region is active, it is used
474 as the link text."
475 (interactive)
476 (markdown-wrap-or-insert "[[" "]]")
477 (backward-char 2))
479 (defun markdown-insert-image ()
480 "Inserts an inline image tag of the form ![]().
481 If Transient Mark mode is on and a region is active, it is used
482 as the alt text of the image."
483 (interactive)
484 (markdown-wrap-or-insert "![" "]")
485 (insert "()")
486 (backward-char 1))
488 (defun markdown-insert-header-1 ()
489 "Inserts a first level atx-style (hash mark) header.
490 If Transient Mark mode is on and a region is active, it is used
491 as the header text."
492 (interactive)
493 (markdown-insert-header 1))
495 (defun markdown-insert-header-2 ()
496 "Inserts a second level atx-style (hash mark) header.
497 If Transient Mark mode is on and a region is active, it is used
498 as the header text."
499 (interactive)
500 (markdown-insert-header 2))
502 (defun markdown-insert-header-3 ()
503 "Inserts a third level atx-style (hash mark) header.
504 If Transient Mark mode is on and a region is active, it is used
505 as the header text."
506 (interactive)
507 (markdown-insert-header 3))
509 (defun markdown-insert-header-4 ()
510 "Inserts a fourth level atx-style (hash mark) header.
511 If Transient Mark mode is on and a region is active, it is used
512 as the header text."
513 (interactive)
514 (markdown-insert-header 4))
516 (defun markdown-insert-header-5 ()
517 "Inserts a fifth level atx-style (hash mark) header.
518 If Transient Mark mode is on and a region is active, it is used
519 as the header text."
520 (interactive)
521 (markdown-insert-header 5))
523 (defun markdown-insert-header (n)
524 "Inserts an atx-style (hash mark) header.
525 With no prefix argument, insert a level-1 header. With prefix N,
526 insert a level-N header. If Transient Mark mode is on and the
527 region is active, it is used as the header text."
528 (interactive "p")
529 (unless n ; Test to see if n is defined
530 (setq n 1)) ; Default to level 1 header
531 (let (hdr)
532 (dotimes (count n hdr)
533 (setq hdr (concat "#" hdr))) ; Build a hash mark header string
534 (setq hdrl (concat hdr " "))
535 (setq hdrr (concat " " hdr))
536 (markdown-wrap-or-insert hdrl hdrr))
537 (backward-char (+ 1 n)))
539 (defun markdown-insert-title ()
540 "Insert a setext-style (underline) first level header.
541 If Transient Mark mode is on and a region is active, it is used
542 as the header text."
543 (interactive)
544 (if (and transient-mark-mode mark-active)
545 (let ((a (region-beginning))
546 (b (region-end))
547 (len 0)
548 (hdr))
549 (setq len (- b a))
550 (dotimes (count len hdr)
551 (setq hdr (concat "=" hdr))) ; Build a === title underline
552 (end-of-line)
553 (insert "\n" hdr "\n"))
554 (insert "\n==========\n")
555 (backward-char 12)))
557 (defun markdown-insert-section ()
558 "Insert a setext-style (underline) second level header.
559 If Transient Mark mode is on and a region is active, it is used
560 as the header text."
561 (interactive)
562 (if (and transient-mark-mode mark-active)
563 (let ((a (region-beginning))
564 (b (region-end))
565 (len 0)
566 (hdr))
567 (setq len (- b a))
568 (dotimes (count len hdr)
569 (setq hdr (concat "-" hdr))) ; Build a --- section underline
570 (end-of-line)
571 (insert "\n" hdr "\n"))
572 (insert "\n----------\n")
573 (backward-char 12)))
575 (defun markdown-insert-blockquote ()
576 "Start a blockquote section (or blockquote the region).
577 If Transient Mark mode is on and a region is active, it is used as
578 the blockquote text."
579 (interactive)
580 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
581 (markdown-blockquote-region)
582 (insert "> ")))
584 (defun markdown-blockquote-region (beg end &optional arg)
585 "Blockquote the region."
586 (interactive "*r\nP")
587 (if mark-active
588 (perform-replace "^" "> " nil 1 nil nil nil beg end)))
590 (defun markdown-insert-pre ()
591 "Start a preformatted section (or apply to the region).
592 If Transient Mark mode is on and a region is active, it is marked
593 as preformatted text."
594 (interactive)
595 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
596 (markdown-pre-region)
597 (insert " ")))
599 (defun markdown-pre-region (beg end &optional arg)
600 "Format the region as preformatted text."
601 (interactive "*r\nP")
602 (if mark-active
603 (perform-replace "^" " " nil 1 nil nil nil beg end)))
608 ;;; Keymap ====================================================================
610 (defvar markdown-mode-map
611 (let ((markdown-mode-map (make-keymap)))
612 ;; Element insertion
613 (define-key markdown-mode-map "\C-c\C-al" 'markdown-insert-link)
614 (define-key markdown-mode-map "\C-c\C-aw" 'markdown-insert-wiki-link)
615 (define-key markdown-mode-map "\C-c\C-ii" 'markdown-insert-image)
616 (define-key markdown-mode-map "\C-c\C-t1" 'markdown-insert-header-1)
617 (define-key markdown-mode-map "\C-c\C-t2" 'markdown-insert-header-2)
618 (define-key markdown-mode-map "\C-c\C-t3" 'markdown-insert-header-3)
619 (define-key markdown-mode-map "\C-c\C-t4" 'markdown-insert-header-4)
620 (define-key markdown-mode-map "\C-c\C-t5" 'markdown-insert-header-5)
621 (define-key markdown-mode-map "\C-c\C-pb" 'markdown-insert-bold)
622 (define-key markdown-mode-map "\C-c\C-ss" 'markdown-insert-bold)
623 (define-key markdown-mode-map "\C-c\C-pi" 'markdown-insert-italic)
624 (define-key markdown-mode-map "\C-c\C-se" 'markdown-insert-italic)
625 (define-key markdown-mode-map "\C-c\C-pf" 'markdown-insert-code)
626 (define-key markdown-mode-map "\C-c\C-sc" 'markdown-insert-code)
627 (define-key markdown-mode-map "\C-c\C-sb" 'markdown-insert-blockquote)
628 (define-key markdown-mode-map "\C-c\C-s\C-b" 'markdown-blockquote-region)
629 (define-key markdown-mode-map "\C-c\C-sp" 'markdown-insert-pre)
630 (define-key markdown-mode-map "\C-c\C-s\C-p" 'markdown-pre-region)
631 (define-key markdown-mode-map "\C-c-" 'markdown-insert-hr)
632 (define-key markdown-mode-map "\C-c\C-tt" 'markdown-insert-title)
633 (define-key markdown-mode-map "\C-c\C-ts" 'markdown-insert-section)
634 ;; Markdown functions
635 (define-key markdown-mode-map "\C-c\C-cm" 'markdown)
636 (define-key markdown-mode-map "\C-c\C-cp" 'markdown-preview)
637 ;; References
638 (define-key markdown-mode-map "\C-c\C-cc" 'markdown-check-refs)
639 markdown-mode-map)
640 "Keymap for Markdown major mode")
642 ;;; Menu ==================================================================
644 (easy-menu-define markdown-mode-menu markdown-mode-map
645 "Menu for Markdown mode"
646 '("Markdown"
647 ["Compile" markdown]
648 ["Preview" markdown-preview]
649 "---"
650 ("Headers (setext)"
651 ["Insert Title" markdown-insert-title]
652 ["Insert Section" markdown-insert-section])
653 ("Headers (atx)"
654 ["First level" markdown-insert-header-1]
655 ["Second level" markdown-insert-header-2]
656 ["Third level" markdown-insert-header-3]
657 ["Fourth level" markdown-insert-header-4]
658 ["Fifth level" markdown-insert-header-5])
659 "---"
660 ["Bold" markdown-insert-bold]
661 ["Italic" markdown-insert-italic]
662 ["Blockquote" markdown-insert-blockquote]
663 ["Preformatted" markdown-insert-pre]
664 ["Code" markdown-insert-code]
665 "---"
666 ["Insert inline link" markdown-insert-link]
667 ["Insert image" markdown-insert-image]
668 ["Insert horizontal rule" markdown-insert-hr]
669 "---"
670 ["Check references" markdown-check-refs]
671 "---"
672 ["Version" markdown-show-version]
677 ;;; References ================================================================
679 ;;; Undefined reference checking code by Dmitry Dzhus <mail@sphinx.net.ru>.
681 (defconst markdown-refcheck-buffer
682 "*Undefined references for %BUFFER%*"
683 "Name of buffer which will contain a list of undefined
684 references in `markdown-mode' buffer named %BUFFER%.")
686 (defun markdown-has-reference-definition (reference)
687 "Find out whether Markdown REFERENCE is defined.
689 REFERENCE should include the square brackets, like [this]."
690 (let ((reference (downcase reference)))
691 (save-excursion
692 (goto-char (point-min))
693 (catch 'found
694 (while (re-search-forward markdown-regex-reference-definition nil t)
695 (when (string= reference (downcase (match-string-no-properties 1)))
696 (throw 'found t)))))))
698 (defun markdown-get-undefined-refs ()
699 "Return a list of undefined Markdown references.
701 Result is an alist of pairs (reference . occurencies), where
702 occurencies is itself another alist of pairs (label .
703 line-number).
705 For example, an alist corresponding to [Nice editor][Emacs] at line 12,
706 \[GNU Emacs][Emacs] at line 45 and [manual][elisp] at line 127 is
707 \((\"[emacs]\" (\"[Nice editor]\" . 12) (\"[GNU Emacs]\" . 45)) (\"[elisp]\" (\"[manual]\" . 127)))."
708 (let ((missing))
709 (save-excursion
710 (goto-char (point-min))
711 (while
712 (re-search-forward markdown-regex-link-reference nil t)
713 (let* ((label (match-string-no-properties 1))
714 (reference (match-string-no-properties 2))
715 (target (downcase (if (string= reference "[]") label reference))))
716 (unless (markdown-has-reference-definition target)
717 (let ((entry (assoc target missing)))
718 (if (not entry)
719 (add-to-list 'missing (cons target
720 (list (cons label (markdown-line-number-at-pos)))) t)
721 (setcdr entry
722 (append (cdr entry) (list (cons label (markdown-line-number-at-pos))))))))))
723 missing)))
725 (defun markdown-add-missing-ref-definition (ref buffer &optional recheck)
726 "Add blank REF definition to the end of BUFFER.
728 REF is a Markdown reference in square brackets, like \"[lisp-history]\".
730 When RECHECK is non-nil, BUFFER gets rechecked for undefined
731 references so that REF disappears from the list of those links."
732 (with-current-buffer buffer
733 (when (not (eq major-mode 'markdown-mode))
734 (error "Not available in current mdoe"))
735 (goto-char (point-max))
736 (indent-new-comment-line)
737 (insert (concat ref ": ")))
738 (switch-to-buffer-other-window buffer)
739 (goto-char (point-max))
740 (when recheck
741 (markdown-check-refs t)))
743 ;; Button which adds an empty Markdown reference definition to the end
744 ;; of buffer specified as its 'target-buffer property. Reference name
745 ;; is button's label
746 (when (>= emacs-major-version 22)
747 (define-button-type 'markdown-ref-button
748 'help-echo "Push to create an empty reference definition"
749 'face 'bold
750 'action (lambda (b)
751 (markdown-add-missing-ref-definition
752 (button-label b) (button-get b 'target-buffer) t))))
754 ;; Button jumping to line in buffer specified as its 'target-buffer
755 ;; property. Line number is button's 'line property.
756 (when (>= emacs-major-version 22)
757 (define-button-type 'goto-line-button
758 'help-echo "Push to go to this line"
759 'face 'italic
760 'action (lambda (b)
761 (message (button-get b 'buffer))
762 (switch-to-buffer-other-window (button-get b 'target-buffer))
763 (goto-line (button-get b 'target-line)))))
765 (defun markdown-check-refs (&optional silent)
766 "Show all undefined Markdown references in current `markdown-mode' buffer.
768 If SILENT is non-nil, do not message anything when no undefined
769 references found.
771 Links which have empty reference definitions are considered to be
772 defined."
773 (interactive "P")
774 (when (not (eq major-mode 'markdown-mode))
775 (error "Not available in current mode"))
776 (let ((oldbuf (current-buffer))
777 (refs (markdown-get-undefined-refs))
778 (refbuf (get-buffer-create (replace-regexp-in-string
779 "%BUFFER%" (buffer-name)
780 markdown-refcheck-buffer t))))
781 (if (null refs)
782 (progn
783 (when (not silent)
784 (message "No undefined references found"))
785 (kill-buffer refbuf))
786 (with-current-buffer refbuf
787 (when view-mode
788 (View-exit-and-edit))
789 (erase-buffer)
790 (insert "Following references lack definitions:")
791 (newline 2)
792 (dolist (ref refs)
793 (let ((button-label (format "%s" (car ref))))
794 (if (>= emacs-major-version 22)
795 ;; Create a reference button in Emacs 22
796 (insert-text-button button-label
797 :type 'markdown-ref-button
798 'target-buffer oldbuf)
799 ;; Insert reference as text in Emacs < 22
800 (insert button-label)))
801 (insert " (")
802 (dolist (occurency (cdr ref))
803 (let ((line (cdr occurency)))
804 (if (>= emacs-major-version 22)
805 ;; Create a line number button in Emacs 22
806 (insert-button (number-to-string line)
807 :type 'goto-line-button
808 'target-buffer oldbuf
809 'target-line line)
810 ;; Insert line number as text in Emacs < 22
811 (insert (number-to-string line)))
812 (insert " "))) (delete-backward-char 1)
813 (insert ")")
814 (newline))
815 (view-buffer-other-window refbuf)
816 (goto-line 4)))))
818 ;;; Commands ==================================================================
820 (defun markdown ()
821 "Run markdown on the current buffer and preview the output in another buffer."
822 (interactive)
823 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
824 (shell-command-on-region (region-beginning) (region-end) markdown-command
825 "*markdown-output*" nil)
826 (shell-command-on-region (point-min) (point-max) markdown-command
827 "*markdown-output*" nil)))
829 (defun markdown-preview ()
830 "Run markdown on the current buffer and preview the output in a browser."
831 (interactive)
832 (markdown)
833 (browse-url-of-buffer "*markdown-output*"))
836 ;;; Miscellaneous =============================================================
838 (defun markdown-line-number-at-pos (&optional pos)
839 "Return (narrowed) buffer line number at position POS.
840 If POS is nil, use current buffer location.
841 This is an exact copy of line-number-at-pos for use in emacs21."
842 (let ((opoint (or pos (point))) start)
843 (save-excursion
844 (goto-char (point-min))
845 (setq start (point))
846 (goto-char opoint)
847 (forward-line 0)
848 (1+ (count-lines start (point))))))
852 ;;; Mode definition ==========================================================
854 (defun markdown-show-version ()
855 "Show the version number in the minibuffer."
856 (interactive)
857 (message "markdown-mode, version %s" markdown-mode-version))
859 (define-derived-mode markdown-mode text-mode "Markdown"
860 "Major mode for editing Markdown files."
861 ;; Font lock.
862 (set (make-local-variable 'font-lock-defaults)
863 '(markdown-mode-font-lock-keywords))
864 (set (make-local-variable 'font-lock-multiline) t)
865 ;; For menu support in XEmacs
866 (easy-menu-add markdown-mode-menu markdown-mode-map))
868 ;(add-to-list 'auto-mode-alist '("\\.text$" . markdown-mode))
870 (provide 'markdown-mode)
872 ;;; markdown-mode.el ends here