support different faces for headers of level 1-4
[markdown-mode/intrigeri.git] / markdown-mode.el
blob57dfaa1c74d7cdacc44338cbbf285a1965a95224
1 ;;; markdown-mode.el --- Major mode to edit Markdown files in Emacs
3 ;; Copyright (C) 2007, 2008 Jason Blevins
5 ;; Version: 1.7-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.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!
203 ;;; History:
205 ;; markdown-mode was written and is maintained by Jason Blevins. The
206 ;; first revision, 1.1, was released on May 24, 2007.
211 ;;; Code:
213 (require 'easymenu)
214 (require 'outline)
216 ;;; User Customizable Variables ===============================================
218 ;; To enable LaTeX/itex syntax highlighting, change to
219 ;; (defvar markdown-enable-itex t)
220 (defvar markdown-enable-itex nil)
223 ;;; Customizable variables ====================================================
225 ;; Current revision
226 (defconst markdown-mode-version "1.7-dev")
228 ;; A hook for users to run their own code when the mode is loaded.
229 (defvar markdown-mode-hook nil)
232 ;;; Customizable variables ====================================================
234 (defgroup markdown nil
235 "Major mode for editing text files in Markdown format."
236 :prefix "markdown-"
237 :group 'wp
238 :link '(url-link "http://jblevins.org/projects/markdown-mode/"))
240 (defcustom markdown-command "markdown"
241 "Command to run markdown."
242 :group 'markdown
243 :type 'string)
245 (defcustom markdown-hr-length 5
246 "Length of horizonal rules."
247 :group 'markdown
248 :type 'integer)
250 (defcustom markdown-bold-underscore nil
251 "Use two underscores for bold instead of two asterisks."
252 :group 'markdown
253 :type 'boolean)
255 (defcustom markdown-italic-underscore nil
256 "Use underscores for italic instead of asterisks."
257 :group 'markdown
258 :type 'boolean)
261 ;;; Font lock =================================================================
263 (require 'font-lock)
265 (defgroup markdown-faces nil
266 "Faces used in Markdown Mode"
267 :group 'markdown
268 :group 'faces)
270 (defcustom markdown-italic-face 'font-lock-variable-name-face
271 "Italic text."
272 :group 'markdown-faces
273 :type '(face))
275 (defcustom markdown-bold-face 'font-lock-type-face
276 "Bold text."
277 :group 'markdown-faces
278 :type '(face))
280 (defcustom markdown-header-face-1 'font-lock-function-name-face
281 "Level 1 headers."
282 :group 'markdown-faces
283 :type '(face))
285 (defcustom markdown-header-face-2 'font-lock-function-name-face
286 "Level 2 headers."
287 :group 'markdown-faces
288 :type '(face))
290 (defcustom markdown-header-face-3 'font-lock-function-name-face
291 "Level 3 headers."
292 :group 'markdown-faces
293 :type '(face))
295 (defcustom markdown-header-face-4 'font-lock-function-name-face
296 "Level 4 headers."
297 :group 'markdown-faces
298 :type '(face))
300 (defcustom markdown-inline-code-face 'font-lock-builtin-face
301 "Inline code."
302 :group 'markdown-faces
303 :type '(face))
305 (defcustom markdown-list-face 'font-lock-variable-name-face
306 "List item markers."
307 :group 'markdown-faces
308 :type '(face))
310 (defcustom markdown-blockquote-face 'font-lock-comment-face
311 "Blockquote sections and preformatted text."
312 :group 'markdown-faces
313 :type '(face))
315 (defcustom markdown-link-face 'font-lock-constant-face
316 "Link text."
317 :group 'markdown-faces
318 :type '(face))
320 (defcustom markdown-reference-face 'font-lock-type-face
321 "Link references."
322 :group 'markdown-faces
323 :type '(face))
325 (defcustom markdown-url-face 'font-lock-string-face
326 "URLs."
327 :group 'markdown-faces
328 :type '(face))
330 (defcustom markdown-math-face 'font-lock-builtin-face
331 "LaTeX expressions."
332 :group 'markdown-faces
333 :type '(face))
335 (defconst markdown-regex-link-inline
336 "\\(!?\\[[^]]*?\\]\\)\\(([^\\)]*)\\)"
337 "Regular expression for a [text](file) or an image link ![text](file).")
339 (defconst markdown-regex-link-reference
340 "\\(!?\\[[^]]+?\\]\\)[ ]?\\(\\[[^]]*?\\]\\)"
341 "Regular expression for a reference link [text][id].")
343 (defconst markdown-regex-reference-definition
344 "^ \\{0,3\\}\\(\\[.+?\\]\\):\\s *\\(.*?\\)\\s *\\( \"[^\"]*\"$\\|$\\)"
345 "Regular expression for a link definition [id]: ...")
347 (defconst markdown-regex-header-1-atx
348 "^\\(# \\)\\(.*?\\)\\($\\| #+$\\)"
349 "Regular expression for level 1 atx-style (hash mark) headers.")
351 (defconst markdown-regex-header-2-atx
352 "^\\(## \\)\\(.*?\\)\\($\\| #+$\\)"
353 "Regular expression for level 2 atx-style (hash mark) headers.")
355 (defconst markdown-regex-header-3-atx
356 "^\\(### \\)\\(.*?\\)\\($\\| #+$\\)"
357 "Regular expression for level 3 atx-style (hash mark) headers.")
359 (defconst markdown-regex-header-4-atx
360 "^\\(#### \\)\\(.*?\\)\\($\\| #+$\\)"
361 "Regular expression for level 4 atx-style (hash mark) headers.")
363 (defconst markdown-regex-header-1-setext
364 "^\\(.*\\)\n\\(===+\\)$"
365 "Regular expression for level 1 setext-style (underline) headers.")
367 (defconst markdown-regex-header-2-setext
368 "^\\(.*\\)\n\\(---+\\)$"
369 "Regular expression for level 2 setext-style (underline) headers.")
371 (defconst markdown-regex-hr
372 "^\\(\\*[ ]?\\*[ ]?\\*[ ]?[\\* ]*\\|-[ ]?-[ ]?-[--- ]*\\)$"
373 "Regular expression for matching Markdown horizontal rules.")
375 (defconst markdown-regex-code
376 "\\(^\\|[^\\]\\)\\(\\(`\\{1,2\\}\\)\\([^ \\]\\|[^ ].*?[^ \\]\\)\\3\\)"
377 "Regular expression for matching inline code fragments.")
379 (defconst markdown-regex-pre
380 "^ .*$"
381 "Regular expression for matching preformatted text sections.")
383 (defconst markdown-regex-list
384 "^[ \t]*\\([0-9]+\\.\\|[\\*\\+-]\\) "
385 "Regular expression for matching list markers.")
387 (defconst markdown-regex-bold
388 "\\(^\\|[^\\]\\)\\(\\([*_]\\{2\\}\\)\\(.\\|\n\\)*?[^\\ ]\\3\\)"
389 "Regular expression for matching bold text.")
391 (defconst markdown-regex-italic
392 "\\(^\\|[^\\]\\)\\(\\([*_]\\)\\([^ \\]\\3\\|[^ ]\\(.\\|\n\\)*?[^\\ ]\\3\\)\\)"
393 "Regular expression for matching italic text.")
395 (defconst markdown-regex-blockquote
396 "^>.*$"
397 "Regular expression for matching blockquote lines.")
399 (defconst markdown-regex-line-break
400 " $"
401 "Regular expression for matching line breaks.")
403 (defconst markdown-regex-wiki-link
404 "\\[\\[[^]]+\\]\\]"
405 "Regular expression for matching wiki links.")
407 (defconst markdown-regex-uri
408 "<\\(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\\)://[^>]*>"
409 "Regular expression for matching inline URIs.")
411 (defconst markdown-regex-email
412 "<\\(\\sw\\|\\s_\\|\\s.\\)+@\\(\\sw\\|\\s_\\|\\s.\\)+>"
413 "Regular expression for matching inline email addresses.")
415 (defconst markdown-regex-latex-expression
416 "\\(^\\|[^\\]\\)\\(\\$\\($\\([^\\$]\\|\\\\.\\)*\\$\\|\\([^\\$]\\|\\\\.\\)*\\)\\$\\)"
417 "Regular expression for itex $..$ or $$..$$ math mode expressions.")
419 (defconst markdown-regex-latex-display
420 "^\\\\\\[\\(.\\|\n\\)*?\\\\\\]$"
421 "Regular expression for itex \[..\] display mode expressions.")
423 (defconst markdown-mode-font-lock-keywords-basic
424 (list
425 (cons markdown-regex-code '(2 markdown-inline-code-face))
426 (cons markdown-regex-pre markdown-blockquote-face)
427 (cons markdown-regex-blockquote markdown-blockquote-face)
428 (cons markdown-regex-header-1-setext markdown-header-face-1)
429 (cons markdown-regex-header-2-setext markdown-header-face-2)
430 (cons markdown-regex-header-1-atx markdown-header-face-1)
431 (cons markdown-regex-header-2-atx markdown-header-face-2)
432 (cons markdown-regex-header-3-atx markdown-header-face-3)
433 (cons markdown-regex-header-4-atx markdown-header-face-4)
434 (cons markdown-regex-hr markdown-header-face-1)
435 (cons markdown-regex-list markdown-list-face)
436 (cons markdown-regex-link-inline
437 '((1 markdown-link-face t)
438 (2 markdown-url-face t)))
439 (cons markdown-regex-link-reference
440 '((1 markdown-link-face t)
441 (2 markdown-reference-face t)))
442 (cons markdown-regex-reference-definition
443 '((1 markdown-reference-face t)
444 (2 markdown-url-face t)
445 (3 markdown-link-face t)))
446 (cons markdown-regex-wiki-link markdown-link-face)
447 (cons markdown-regex-bold '(2 markdown-bold-face))
448 (cons markdown-regex-italic '(2 markdown-italic-face))
449 (cons markdown-regex-uri markdown-link-face)
450 (cons markdown-regex-email markdown-link-face))
451 "Syntax highlighting for Markdown files.")
454 ;; Includes additional Latex/itex/Instiki font lock keywords
455 (defconst markdown-mode-font-lock-keywords-itex
456 (append
457 (list
458 ;; itex math mode $..$ or $$..$$
459 (cons markdown-regex-latex-expression '(2 markdown-math-face))
460 ;; Display mode equations with brackets: \[ \]
461 (cons markdown-regex-latex-display markdown-math-face)
462 ;; Equation reference (eq:foo)
463 (cons "(eq:\\w+)" markdown-reference-face)
464 ;; Equation reference \eqref
465 (cons "\\\\eqref{\\w+}" markdown-reference-face))
466 markdown-mode-font-lock-keywords-basic)
467 "Syntax highlighting for Markdown, itex, and wiki expressions.")
470 (defvar markdown-mode-font-lock-keywords
471 (if markdown-enable-itex
472 markdown-mode-font-lock-keywords-itex
473 markdown-mode-font-lock-keywords-basic)
474 "Default highlighting expressions for Markdown mode.")
478 ;;; Syntax Table ==============================================================
480 (defvar markdown-mode-syntax-table
481 (let ((markdown-mode-syntax-table (make-syntax-table)))
482 (modify-syntax-entry ?\" "w" markdown-mode-syntax-table)
483 markdown-mode-syntax-table)
484 "Syntax table for `markdown-mode'.")
488 ;;; Element Insertion =========================================================
490 (defun markdown-wrap-or-insert (s1 s2)
491 "Insert the strings S1 and S2.
492 If Transient Mark mode is on and a region is active, wrap the strings S1
493 and S2 around the region."
494 (if (and transient-mark-mode mark-active)
495 (let ((a (region-beginning)) (b (region-end)))
496 (goto-char a)
497 (insert s1)
498 (goto-char (+ b (length s1)))
499 (insert s2))
500 (insert s1 s2)))
502 (defun markdown-insert-hr ()
503 "Insert a horizonal rule."
504 (interactive)
505 (let (hr)
506 (dotimes (count (- markdown-hr-length 1) hr) ; Count to n - 1
507 (setq hr (concat "* " hr))) ; Build HR string
508 (setq hr (concat hr "*\n")) ; Add the n-th *
509 (insert hr)))
511 (defun markdown-insert-bold ()
512 "Insert markup for a bold word or phrase.
513 If Transient Mark mode is on and a region is active, it is made bold."
514 (interactive)
515 (if markdown-bold-underscore
516 (markdown-wrap-or-insert "__" "__")
517 (markdown-wrap-or-insert "**" "**"))
518 (backward-char 2))
520 (defun markdown-insert-italic ()
521 "Insert markup for an italic word or phrase.
522 If Transient Mark mode is on and a region is active, it is made italic."
523 (interactive)
524 (if markdown-italic-underscore
525 (markdown-wrap-or-insert "_" "_")
526 (markdown-wrap-or-insert "*" "*"))
527 (backward-char 1))
529 (defun markdown-insert-code ()
530 "Insert markup for an inline code fragment.
531 If Transient Mark mode is on and a region is active, it is marked
532 as inline code."
533 (interactive)
534 (markdown-wrap-or-insert "`" "`")
535 (backward-char 1))
537 (defun markdown-insert-link ()
538 "Insert an inline link of the form []().
539 If Transient Mark mode is on and a region is active, it is used
540 as the link text."
541 (interactive)
542 (markdown-wrap-or-insert "[" "]")
543 (insert "()")
544 (backward-char 1))
546 (defun markdown-insert-wiki-link ()
547 "Insert a wiki link of the form [[WikiLink]].
548 If Transient Mark mode is on and a region is active, it is used
549 as the link text."
550 (interactive)
551 (markdown-wrap-or-insert "[[" "]]")
552 (backward-char 2))
554 (defun markdown-insert-image ()
555 "Insert an inline image tag of the form ![]().
556 If Transient Mark mode is on and a region is active, it is used
557 as the alt text of the image."
558 (interactive)
559 (markdown-wrap-or-insert "![" "]")
560 (insert "()")
561 (backward-char 1))
563 (defun markdown-insert-header-1 ()
564 "Insert a first level atx-style (hash mark) header.
565 If Transient Mark mode is on and a region is active, it is used
566 as the header text."
567 (interactive)
568 (markdown-insert-header 1))
570 (defun markdown-insert-header-2 ()
571 "Insert a second level atx-style (hash mark) header.
572 If Transient Mark mode is on and a region is active, it is used
573 as the header text."
574 (interactive)
575 (markdown-insert-header 2))
577 (defun markdown-insert-header-3 ()
578 "Insert a third level atx-style (hash mark) header.
579 If Transient Mark mode is on and a region is active, it is used
580 as the header text."
581 (interactive)
582 (markdown-insert-header 3))
584 (defun markdown-insert-header-4 ()
585 "Insert a fourth level atx-style (hash mark) header.
586 If Transient Mark mode is on and a region is active, it is used
587 as the header text."
588 (interactive)
589 (markdown-insert-header 4))
591 (defun markdown-insert-header-5 ()
592 "Insert a fifth level atx-style (hash mark) header.
593 If Transient Mark mode is on and a region is active, it is used
594 as the header text."
595 (interactive)
596 (markdown-insert-header 5))
598 (defun markdown-insert-header (n)
599 "Insert an atx-style (hash mark) header.
600 With no prefix argument, insert a level-1 header. With prefix N,
601 insert a level-N header. If Transient Mark mode is on and the
602 region is active, it is used as the header text."
603 (interactive "p")
604 (unless n ; Test to see if n is defined
605 (setq n 1)) ; Default to level 1 header
606 (let (hdr hdrl hdrr)
607 (dotimes (count n hdr)
608 (setq hdr (concat "#" hdr))) ; Build a hash mark header string
609 (setq hdrl (concat hdr " "))
610 (setq hdrr (concat " " hdr))
611 (markdown-wrap-or-insert hdrl hdrr))
612 (backward-char (+ 1 n)))
614 (defun markdown-insert-title ()
615 "Insert a setext-style (underline) first level header.
616 If Transient Mark mode is on and a region is active, it is used
617 as the header text."
618 (interactive)
619 (if (and transient-mark-mode mark-active)
620 (let ((a (region-beginning))
621 (b (region-end))
622 (len 0)
623 (hdr))
624 (setq len (- b a))
625 (dotimes (count len hdr)
626 (setq hdr (concat "=" hdr))) ; Build a === title underline
627 (end-of-line)
628 (insert "\n" hdr "\n"))
629 (insert "\n==========\n")
630 (backward-char 12)))
632 (defun markdown-insert-section ()
633 "Insert a setext-style (underline) second level header.
634 If Transient Mark mode is on and a region is active, it is used
635 as the header text."
636 (interactive)
637 (if (and transient-mark-mode mark-active)
638 (let ((a (region-beginning))
639 (b (region-end))
640 (len 0)
641 (hdr))
642 (setq len (- b a))
643 (dotimes (count len hdr)
644 (setq hdr (concat "-" hdr))) ; Build a --- section underline
645 (end-of-line)
646 (insert "\n" hdr "\n"))
647 (insert "\n----------\n")
648 (backward-char 12)))
650 (defun markdown-insert-blockquote ()
651 "Start a blockquote section (or blockquote the region).
652 If Transient Mark mode is on and a region is active, it is used as
653 the blockquote text."
654 (interactive)
655 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
656 (markdown-blockquote-region (region-beginning) (region-end))
657 (insert "> ")))
659 (defun markdown-block-region (beg end prefix)
660 "Format the region using a block prefix.
661 The characters PREFIX will appear at the beginning of each line.
662 Arguments BEG and END specify the beginning and end of the
663 region."
664 (if mark-active
665 (save-excursion
666 (let ((endpos end))
667 ; Ensure that there is a leading blank line
668 (goto-char beg)
669 (while (not (looking-back "\n\n" 2))
670 (insert "\n")
671 (setq endpos (+ 1 endpos)))
672 ; Insert blockquote characters
673 (move-to-left-margin)
674 (while (< (point-at-bol) endpos)
675 (insert prefix)
676 (setq endpos (+ (length prefix) endpos))
677 (forward-line))
678 ; Move back before any blank lines at the end
679 (goto-char endpos)
680 (while (looking-back "\n" 1)
681 (backward-char))
682 ; Ensure one blank line at the end
683 (while (not (looking-at "\n\n"))
684 (insert "\n")
685 (backward-char))))))
687 (defun markdown-blockquote-region (beg end)
688 "Blockquote the region.
689 Arguments BEG and END specify the beginning and end of the region."
690 (interactive "*r")
691 (markdown-block-region beg end "> "))
693 (defun markdown-insert-pre ()
694 "Start a preformatted section (or apply to the region).
695 If Transient Mark mode is on and a region is active, it is marked
696 as preformatted text."
697 (interactive)
698 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
699 (markdown-pre-region (region-beginning) (region-end))
700 (insert " ")))
702 (defun markdown-pre-region (beg end)
703 "Format the region as preformatted text.
704 Arguments BEG and END specify the beginning and end of the region."
705 (interactive "*r")
706 (markdown-block-region beg end " "))
711 ;;; Keymap ====================================================================
713 (defvar markdown-mode-map
714 (let ((markdown-mode-map (make-keymap)))
715 ;; Element insertion
716 (define-key markdown-mode-map "\C-c\C-al" 'markdown-insert-link)
717 (define-key markdown-mode-map "\C-c\C-aw" 'markdown-insert-wiki-link)
718 (define-key markdown-mode-map "\C-c\C-ii" 'markdown-insert-image)
719 (define-key markdown-mode-map "\C-c\C-t1" 'markdown-insert-header-1)
720 (define-key markdown-mode-map "\C-c\C-t2" 'markdown-insert-header-2)
721 (define-key markdown-mode-map "\C-c\C-t3" 'markdown-insert-header-3)
722 (define-key markdown-mode-map "\C-c\C-t4" 'markdown-insert-header-4)
723 (define-key markdown-mode-map "\C-c\C-t5" 'markdown-insert-header-5)
724 (define-key markdown-mode-map "\C-c\C-pb" 'markdown-insert-bold)
725 (define-key markdown-mode-map "\C-c\C-ss" 'markdown-insert-bold)
726 (define-key markdown-mode-map "\C-c\C-pi" 'markdown-insert-italic)
727 (define-key markdown-mode-map "\C-c\C-se" 'markdown-insert-italic)
728 (define-key markdown-mode-map "\C-c\C-pf" 'markdown-insert-code)
729 (define-key markdown-mode-map "\C-c\C-sc" 'markdown-insert-code)
730 (define-key markdown-mode-map "\C-c\C-sb" 'markdown-insert-blockquote)
731 (define-key markdown-mode-map "\C-c\C-s\C-b" 'markdown-blockquote-region)
732 (define-key markdown-mode-map "\C-c\C-sp" 'markdown-insert-pre)
733 (define-key markdown-mode-map "\C-c\C-s\C-p" 'markdown-pre-region)
734 (define-key markdown-mode-map "\C-c-" 'markdown-insert-hr)
735 (define-key markdown-mode-map "\C-c\C-tt" 'markdown-insert-title)
736 (define-key markdown-mode-map "\C-c\C-ts" 'markdown-insert-section)
737 ;; Visibility cycling
738 (define-key markdown-mode-map (kbd "<tab>") 'markdown-cycle)
739 (define-key markdown-mode-map (kbd "<S-iso-lefttab>") 'markdown-shifttab)
740 ;; Markdown functions
741 (define-key markdown-mode-map "\C-c\C-cm" 'markdown)
742 (define-key markdown-mode-map "\C-c\C-cp" 'markdown-preview)
743 ;; References
744 (define-key markdown-mode-map "\C-c\C-cc" 'markdown-check-refs)
745 markdown-mode-map)
746 "Keymap for Markdown major mode.")
748 ;;; Menu ==================================================================
750 (easy-menu-define markdown-mode-menu markdown-mode-map
751 "Menu for Markdown mode"
752 '("Markdown"
753 ("Show/Hide"
754 ["Cycle visibility" markdown-cycle (outline-on-heading-p)]
755 ["Cycle global visibility" markdown-shifttab])
756 "---"
757 ["Compile" markdown]
758 ["Preview" markdown-preview]
759 "---"
760 ("Headers (setext)"
761 ["Insert Title" markdown-insert-title]
762 ["Insert Section" markdown-insert-section])
763 ("Headers (atx)"
764 ["First level" markdown-insert-header-1]
765 ["Second level" markdown-insert-header-2]
766 ["Third level" markdown-insert-header-3]
767 ["Fourth level" markdown-insert-header-4]
768 ["Fifth level" markdown-insert-header-5])
769 "---"
770 ["Bold" markdown-insert-bold]
771 ["Italic" markdown-insert-italic]
772 ["Blockquote" markdown-insert-blockquote]
773 ["Preformatted" markdown-insert-pre]
774 ["Code" markdown-insert-code]
775 "---"
776 ["Insert inline link" markdown-insert-link]
777 ["Insert image" markdown-insert-image]
778 ["Insert horizontal rule" markdown-insert-hr]
779 "---"
780 ["Check references" markdown-check-refs]
781 "---"
782 ["Version" markdown-show-version]
787 ;;; References ================================================================
789 ;;; Undefined reference checking code by Dmitry Dzhus <mail@sphinx.net.ru>.
791 (defconst markdown-refcheck-buffer
792 "*Undefined references for %BUFFER%*"
793 "Pattern for name of buffer for listing undefined references.
794 The string %BUFFER% will be replaced by the corresponding
795 `markdown-mode' buffer name.")
797 (defun markdown-has-reference-definition (reference)
798 "Find out whether Markdown REFERENCE is defined.
800 REFERENCE should include the square brackets, like [this]."
801 (let ((reference (downcase reference)))
802 (save-excursion
803 (goto-char (point-min))
804 (catch 'found
805 (while (re-search-forward markdown-regex-reference-definition nil t)
806 (when (string= reference (downcase (match-string-no-properties 1)))
807 (throw 'found t)))))))
809 (defun markdown-get-undefined-refs ()
810 "Return a list of undefined Markdown references.
812 Result is an alist of pairs (reference . occurencies), where
813 occurencies is itself another alist of pairs (label .
814 line-number).
816 For example, an alist corresponding to [Nice editor][Emacs] at line 12,
817 \[GNU Emacs][Emacs] at line 45 and [manual][elisp] at line 127 is
818 \((\"[emacs]\" (\"[Nice editor]\" . 12) (\"[GNU Emacs]\" . 45)) (\"[elisp]\" (\"[manual]\" . 127)))."
819 (let ((missing))
820 (save-excursion
821 (goto-char (point-min))
822 (while
823 (re-search-forward markdown-regex-link-reference nil t)
824 (let* ((label (match-string-no-properties 1))
825 (reference (match-string-no-properties 2))
826 (target (downcase (if (string= reference "[]") label reference))))
827 (unless (markdown-has-reference-definition target)
828 (let ((entry (assoc target missing)))
829 (if (not entry)
830 (add-to-list 'missing (cons target
831 (list (cons label (markdown-line-number-at-pos)))) t)
832 (setcdr entry
833 (append (cdr entry) (list (cons label (markdown-line-number-at-pos))))))))))
834 missing)))
836 (defun markdown-add-missing-ref-definition (ref buffer &optional recheck)
837 "Add blank REF definition to the end of BUFFER.
839 REF is a Markdown reference in square brackets, like \"[lisp-history]\".
841 When RECHECK is non-nil, BUFFER gets rechecked for undefined
842 references so that REF disappears from the list of those links."
843 (with-current-buffer buffer
844 (when (not (eq major-mode 'markdown-mode))
845 (error "Not available in current mdoe"))
846 (goto-char (point-max))
847 (indent-new-comment-line)
848 (insert (concat ref ": ")))
849 (switch-to-buffer-other-window buffer)
850 (goto-char (point-max))
851 (when recheck
852 (markdown-check-refs t)))
854 ;; Button which adds an empty Markdown reference definition to the end
855 ;; of buffer specified as its 'target-buffer property. Reference name
856 ;; is button's label
857 (when (>= emacs-major-version 22)
858 (define-button-type 'markdown-ref-button
859 'help-echo "Push to create an empty reference definition"
860 'face 'bold
861 'action (lambda (b)
862 (markdown-add-missing-ref-definition
863 (button-label b) (button-get b 'target-buffer) t))))
865 ;; Button jumping to line in buffer specified as its 'target-buffer
866 ;; property. Line number is button's 'line property.
867 (when (>= emacs-major-version 22)
868 (define-button-type 'goto-line-button
869 'help-echo "Push to go to this line"
870 'face 'italic
871 'action (lambda (b)
872 (message (button-get b 'buffer))
873 (switch-to-buffer-other-window (button-get b 'target-buffer))
874 (goto-line (button-get b 'target-line)))))
876 (defun markdown-check-refs (&optional silent)
877 "Show all undefined Markdown references in current `markdown-mode' buffer.
879 If SILENT is non-nil, do not message anything when no undefined
880 references found.
882 Links which have empty reference definitions are considered to be
883 defined."
884 (interactive "P")
885 (when (not (eq major-mode 'markdown-mode))
886 (error "Not available in current mode"))
887 (let ((oldbuf (current-buffer))
888 (refs (markdown-get-undefined-refs))
889 (refbuf (get-buffer-create (replace-regexp-in-string
890 "%BUFFER%" (buffer-name)
891 markdown-refcheck-buffer t))))
892 (if (null refs)
893 (progn
894 (when (not silent)
895 (message "No undefined references found"))
896 (kill-buffer refbuf))
897 (with-current-buffer refbuf
898 (when view-mode
899 (View-exit-and-edit))
900 (erase-buffer)
901 (insert "Following references lack definitions:")
902 (newline 2)
903 (dolist (ref refs)
904 (let ((button-label (format "%s" (car ref))))
905 (if (>= emacs-major-version 22)
906 ;; Create a reference button in Emacs 22
907 (insert-text-button button-label
908 :type 'markdown-ref-button
909 'target-buffer oldbuf)
910 ;; Insert reference as text in Emacs < 22
911 (insert button-label)))
912 (insert " (")
913 (dolist (occurency (cdr ref))
914 (let ((line (cdr occurency)))
915 (if (>= emacs-major-version 22)
916 ;; Create a line number button in Emacs 22
917 (insert-button (number-to-string line)
918 :type 'goto-line-button
919 'target-buffer oldbuf
920 'target-line line)
921 ;; Insert line number as text in Emacs < 22
922 (insert (number-to-string line)))
923 (insert " "))) (delete-backward-char 1)
924 (insert ")")
925 (newline))
926 (view-buffer-other-window refbuf)
927 (goto-line 4)))))
930 ;;; Outline ===================================================================
932 ;; The following visibility cycling code was taken from org-mode
933 ;; by Carsten Dominik and adapted for markdown-mode.
935 (defvar markdown-cycle-global-status 1)
936 (defvar markdown-cycle-subtree-status nil)
938 ;; Based on org-end-of-subtree from org.el
939 (defun markdown-end-of-subtree (&optional invisible-OK)
940 "Move to the end of the current subtree.
941 Only visible heading lines are considered, unless INVISIBLE-OK is
942 non-nil."
943 (outline-back-to-heading invisible-OK)
944 (let ((first t)
945 (level (funcall outline-level)))
946 (while (and (not (eobp))
947 (or first (> (funcall outline-level) level)))
948 (setq first nil)
949 (outline-next-heading))
950 (if (memq (preceding-char) '(?\n ?\^M))
951 (progn
952 ;; Go to end of line before heading
953 (forward-char -1)
954 (if (memq (preceding-char) '(?\n ?\^M))
955 ;; leave blank line before heading
956 (forward-char -1)))))
957 (point))
959 ;; Based on org-cycle from org.el.
960 (defun markdown-cycle (&optional arg)
961 "Visibility cycling for Markdown mode.
962 If ARG is t, perform global visibility cycling. If the point is
963 at an atx-style header, cycle visibility of the corresponding
964 subtree. Otherwise, insert a tab using `indent-relative'."
965 (interactive "P")
966 (cond
967 ((eq arg t) ;; Global cycling
968 (cond
969 ((and (eq last-command this-command)
970 (eq markdown-cycle-global-status 2))
971 ;; Move from overview to contents
972 (hide-sublevels 1)
973 (message "CONTENTS")
974 (setq markdown-cycle-global-status 3))
976 ((and (eq last-command this-command)
977 (eq markdown-cycle-global-status 3))
978 ;; Move from contents to all
979 (show-all)
980 (message "SHOW ALL")
981 (setq markdown-cycle-global-status 1))
984 ;; Defaults to overview
985 (hide-body)
986 (message "OVERVIEW")
987 (setq markdown-cycle-global-status 2))))
989 ((save-excursion (beginning-of-line 1) (looking-at outline-regexp))
990 ;; At a heading: rotate between three different views
991 (outline-back-to-heading)
992 (let ((goal-column 0) eoh eol eos)
993 ;; Determine boundaries
994 (save-excursion
995 (outline-back-to-heading)
996 (save-excursion
997 (beginning-of-line 2)
998 (while (and (not (eobp)) ;; this is like `next-line'
999 (get-char-property (1- (point)) 'invisible))
1000 (beginning-of-line 2)) (setq eol (point)))
1001 (outline-end-of-heading) (setq eoh (point))
1002 (markdown-end-of-subtree t)
1003 (skip-chars-forward " \t\n")
1004 (beginning-of-line 1) ; in case this is an item
1005 (setq eos (1- (point))))
1006 ;; Find out what to do next and set `this-command'
1007 (cond
1008 ((= eos eoh)
1009 ;; Nothing is hidden behind this heading
1010 (message "EMPTY ENTRY")
1011 (setq markdown-cycle-subtree-status nil))
1012 ((>= eol eos)
1013 ;; Entire subtree is hidden in one line: open it
1014 (show-entry)
1015 (show-children)
1016 (message "CHILDREN")
1017 (setq markdown-cycle-subtree-status 'children))
1018 ((and (eq last-command this-command)
1019 (eq markdown-cycle-subtree-status 'children))
1020 ;; We just showed the children, now show everything.
1021 (show-subtree)
1022 (message "SUBTREE")
1023 (setq markdown-cycle-subtree-status 'subtree))
1025 ;; Default action: hide the subtree.
1026 (hide-subtree)
1027 (message "FOLDED")
1028 (setq markdown-cycle-subtree-status 'folded)))))
1031 (message "TAB")
1032 (indent-relative))))
1034 ;; Based on org-shifttab from org.el.
1035 (defun markdown-shifttab ()
1036 "Global visibility cycling.
1037 Calls `markdown-cycle' with argument t."
1038 (interactive)
1039 (markdown-cycle t))
1041 ;;; Commands ==================================================================
1043 (defun markdown ()
1044 "Run markdown on the current buffer and preview the output in another buffer."
1045 (interactive)
1046 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
1047 (shell-command-on-region (region-beginning) (region-end) markdown-command
1048 "*markdown-output*" nil)
1049 (shell-command-on-region (point-min) (point-max) markdown-command
1050 "*markdown-output*" nil)))
1052 (defun markdown-preview ()
1053 "Run markdown on the current buffer and preview the output in a browser."
1054 (interactive)
1055 (markdown)
1056 (browse-url-of-buffer "*markdown-output*"))
1059 ;;; Miscellaneous =============================================================
1061 (defun markdown-line-number-at-pos (&optional pos)
1062 "Return (narrowed) buffer line number at position POS.
1063 If POS is nil, use current buffer location.
1064 This is an exact copy of `line-number-at-pos' for use in emacs21."
1065 (let ((opoint (or pos (point))) start)
1066 (save-excursion
1067 (goto-char (point-min))
1068 (setq start (point))
1069 (goto-char opoint)
1070 (forward-line 0)
1071 (1+ (count-lines start (point))))))
1075 ;;; Mode definition ==========================================================
1077 (defun markdown-show-version ()
1078 "Show the version number in the minibuffer."
1079 (interactive)
1080 (message "markdown-mode, version %s" markdown-mode-version))
1082 (define-derived-mode markdown-mode text-mode "Markdown"
1083 "Major mode for editing Markdown files."
1084 ;; Font lock.
1085 (set (make-local-variable 'font-lock-defaults)
1086 '(markdown-mode-font-lock-keywords))
1087 (set (make-local-variable 'font-lock-multiline) t)
1088 ;; For menu support in XEmacs
1089 (easy-menu-add markdown-mode-menu markdown-mode-map)
1090 ;; Make filling work with lists
1091 (set (make-local-variable 'paragraph-start)
1092 "\f\\|[ \t]*$\\|^[ \t]*[*+-] \\|^[ \t*][0-9]+\\. ")
1093 ;; Outline mode
1094 (make-local-variable 'outline-regexp)
1095 (setq outline-regexp "#+")
1096 ;; Cause use of ellipses for invisible text.
1097 (add-to-invisibility-spec '(outline . t)))
1099 ;(add-to-list 'auto-mode-alist '("\\.text$" . markdown-mode))
1101 (provide 'markdown-mode)
1103 ;;; markdown-mode.el ends here