make faces really customizable, using defface instead of defcustom
[markdown-mode/intrigeri.git] / markdown-mode.el
blob7af00c00a8f6d019b33903bab0be3b1b43f2e2c0
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 (defvar markdown-italic-face 'markdown-italic-face)
271 (defface markdown-italic-face '((t :inherit font-lock-variable-name-face))
272 "Italic text."
273 :group 'markdown-faces)
275 (defvar markdown-bold-face 'markdown-bold-face)
276 (defface markdown-bold-face '((t :inherit font-lock-type-face))
277 "Bold text."
278 :group 'markdown-faces)
280 (defvar markdown-header-face-1 'markdown-header-face-1)
281 (defface markdown-header-face-1 '((t :inherit markdown-header-face))
282 "Level 1 headers."
283 :group 'markdown-faces)
285 (defvar markdown-header-face-2 'markdown-header-face-2)
286 (defface markdown-header-face-2 '((t :inherit markdown-header-face))
287 "Level 2 headers."
288 :group 'markdown-faces)
290 (defvar markdown-header-face-3 'markdown-header-face-3)
291 (defface markdown-header-face-3 '((t :inherit markdown-header-face))
292 "Level 3 headers."
293 :group 'markdown-faces)
295 (defvar markdown-header-face-4 'markdown-header-face-4)
296 (defface markdown-header-face-4 '((t :inherit markdown-header-face))
297 "Level 4 headers."
298 :group 'markdown-faces)
300 (defvar markdown-inline-code-face 'markdown-inline-code-face)
301 (defface markdown-inline-code-face '((t inherit font-lock-builtin-face))
302 "Inline code."
303 :group 'markdown-faces)
305 (defvar markdown-list-face 'markdown-list-face)
306 (defface markdown-list-face '((t :inherit font-lock-variable-name-face))
307 "List item markers."
308 :group 'markdown-faces)
310 (defvar markdown-blockquote-face 'markdown-blockquote-face)
311 (defface markdown-blockquote-face '((t :inherit font-lock-comment-face))
312 "Blockquote sections and preformatted text."
313 :group 'markdown-faces)
315 (defvar markdown-link-face 'markdown-link-face)
316 (defface markdown-link-face '((t :inherit font-lock-constant-face))
317 "Link text."
318 :group 'markdown-faces)
320 (defvar markdown-reference-face 'markdown-reference-face)
321 (defface markdown-reference-face '((t :inherit font-lock-type-face))
322 "Link references."
323 :group 'markdown-faces)
325 (defvar markdown-url-face 'markdown-url-face)
326 (defface markdown-url-face '((t :inherit font-lock-string-face))
327 "URLs."
328 :group 'markdown-faces)
330 (defvar markdown-math-face 'markdown-math-face)
331 (defface markdown-math-face '((t :inherit font-lock-builtin-face))
332 "LaTeX expressions."
333 :group 'markdown-faces)
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 (defvar 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)
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)
452 "Syntax highlighting for Markdown files.")
455 ;; Includes additional Latex/itex/Instiki font lock keywords
456 (defconst markdown-mode-font-lock-keywords-itex
457 (append
458 (list
459 ;; itex math mode $..$ or $$..$$
460 (cons markdown-regex-latex-expression '(2 markdown-math-face))
461 ;; Display mode equations with brackets: \[ \]
462 (cons markdown-regex-latex-display 'markdown-math-face)
463 ;; Equation reference (eq:foo)
464 (cons "(eq:\\w+)" 'markdown-reference-face)
465 ;; Equation reference \eqref
466 (cons "\\\\eqref{\\w+}" 'markdown-reference-face))
467 markdown-mode-font-lock-keywords-basic)
468 "Syntax highlighting for Markdown, itex, and wiki expressions.")
471 (defvar markdown-mode-font-lock-keywords
472 (if markdown-enable-itex
473 markdown-mode-font-lock-keywords-itex
474 markdown-mode-font-lock-keywords-basic)
475 "Default highlighting expressions for Markdown mode.")
479 ;;; Syntax Table ==============================================================
481 (defvar markdown-mode-syntax-table
482 (let ((markdown-mode-syntax-table (make-syntax-table)))
483 (modify-syntax-entry ?\" "w" markdown-mode-syntax-table)
484 markdown-mode-syntax-table)
485 "Syntax table for `markdown-mode'.")
489 ;;; Element Insertion =========================================================
491 (defun markdown-wrap-or-insert (s1 s2)
492 "Insert the strings S1 and S2.
493 If Transient Mark mode is on and a region is active, wrap the strings S1
494 and S2 around the region."
495 (if (and transient-mark-mode mark-active)
496 (let ((a (region-beginning)) (b (region-end)))
497 (goto-char a)
498 (insert s1)
499 (goto-char (+ b (length s1)))
500 (insert s2))
501 (insert s1 s2)))
503 (defun markdown-insert-hr ()
504 "Insert a horizonal rule."
505 (interactive)
506 (let (hr)
507 (dotimes (count (- markdown-hr-length 1) hr) ; Count to n - 1
508 (setq hr (concat "* " hr))) ; Build HR string
509 (setq hr (concat hr "*\n")) ; Add the n-th *
510 (insert hr)))
512 (defun markdown-insert-bold ()
513 "Insert markup for a bold word or phrase.
514 If Transient Mark mode is on and a region is active, it is made bold."
515 (interactive)
516 (if markdown-bold-underscore
517 (markdown-wrap-or-insert "__" "__")
518 (markdown-wrap-or-insert "**" "**"))
519 (backward-char 2))
521 (defun markdown-insert-italic ()
522 "Insert markup for an italic word or phrase.
523 If Transient Mark mode is on and a region is active, it is made italic."
524 (interactive)
525 (if markdown-italic-underscore
526 (markdown-wrap-or-insert "_" "_")
527 (markdown-wrap-or-insert "*" "*"))
528 (backward-char 1))
530 (defun markdown-insert-code ()
531 "Insert markup for an inline code fragment.
532 If Transient Mark mode is on and a region is active, it is marked
533 as inline code."
534 (interactive)
535 (markdown-wrap-or-insert "`" "`")
536 (backward-char 1))
538 (defun markdown-insert-link ()
539 "Insert an inline link of the form []().
540 If Transient Mark mode is on and a region is active, it is used
541 as the link text."
542 (interactive)
543 (markdown-wrap-or-insert "[" "]")
544 (insert "()")
545 (backward-char 1))
547 (defun markdown-insert-wiki-link ()
548 "Insert a wiki link of the form [[WikiLink]].
549 If Transient Mark mode is on and a region is active, it is used
550 as the link text."
551 (interactive)
552 (markdown-wrap-or-insert "[[" "]]")
553 (backward-char 2))
555 (defun markdown-insert-image ()
556 "Insert an inline image tag of the form ![]().
557 If Transient Mark mode is on and a region is active, it is used
558 as the alt text of the image."
559 (interactive)
560 (markdown-wrap-or-insert "![" "]")
561 (insert "()")
562 (backward-char 1))
564 (defun markdown-insert-header-1 ()
565 "Insert a first level atx-style (hash mark) header.
566 If Transient Mark mode is on and a region is active, it is used
567 as the header text."
568 (interactive)
569 (markdown-insert-header 1))
571 (defun markdown-insert-header-2 ()
572 "Insert a second level atx-style (hash mark) header.
573 If Transient Mark mode is on and a region is active, it is used
574 as the header text."
575 (interactive)
576 (markdown-insert-header 2))
578 (defun markdown-insert-header-3 ()
579 "Insert a third level atx-style (hash mark) header.
580 If Transient Mark mode is on and a region is active, it is used
581 as the header text."
582 (interactive)
583 (markdown-insert-header 3))
585 (defun markdown-insert-header-4 ()
586 "Insert a fourth level atx-style (hash mark) header.
587 If Transient Mark mode is on and a region is active, it is used
588 as the header text."
589 (interactive)
590 (markdown-insert-header 4))
592 (defun markdown-insert-header-5 ()
593 "Insert a fifth level atx-style (hash mark) header.
594 If Transient Mark mode is on and a region is active, it is used
595 as the header text."
596 (interactive)
597 (markdown-insert-header 5))
599 (defun markdown-insert-header (n)
600 "Insert an atx-style (hash mark) header.
601 With no prefix argument, insert a level-1 header. With prefix N,
602 insert a level-N header. If Transient Mark mode is on and the
603 region is active, it is used as the header text."
604 (interactive "p")
605 (unless n ; Test to see if n is defined
606 (setq n 1)) ; Default to level 1 header
607 (let (hdr hdrl hdrr)
608 (dotimes (count n hdr)
609 (setq hdr (concat "#" hdr))) ; Build a hash mark header string
610 (setq hdrl (concat hdr " "))
611 (setq hdrr (concat " " hdr))
612 (markdown-wrap-or-insert hdrl hdrr))
613 (backward-char (+ 1 n)))
615 (defun markdown-insert-title ()
616 "Insert a setext-style (underline) first level header.
617 If Transient Mark mode is on and a region is active, it is used
618 as the header text."
619 (interactive)
620 (if (and transient-mark-mode mark-active)
621 (let ((a (region-beginning))
622 (b (region-end))
623 (len 0)
624 (hdr))
625 (setq len (- b a))
626 (dotimes (count len hdr)
627 (setq hdr (concat "=" hdr))) ; Build a === title underline
628 (end-of-line)
629 (insert "\n" hdr "\n"))
630 (insert "\n==========\n")
631 (backward-char 12)))
633 (defun markdown-insert-section ()
634 "Insert a setext-style (underline) second level header.
635 If Transient Mark mode is on and a region is active, it is used
636 as the header text."
637 (interactive)
638 (if (and transient-mark-mode mark-active)
639 (let ((a (region-beginning))
640 (b (region-end))
641 (len 0)
642 (hdr))
643 (setq len (- b a))
644 (dotimes (count len hdr)
645 (setq hdr (concat "-" hdr))) ; Build a --- section underline
646 (end-of-line)
647 (insert "\n" hdr "\n"))
648 (insert "\n----------\n")
649 (backward-char 12)))
651 (defun markdown-insert-blockquote ()
652 "Start a blockquote section (or blockquote the region).
653 If Transient Mark mode is on and a region is active, it is used as
654 the blockquote text."
655 (interactive)
656 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
657 (markdown-blockquote-region (region-beginning) (region-end))
658 (insert "> ")))
660 (defun markdown-block-region (beg end prefix)
661 "Format the region using a block prefix.
662 The characters PREFIX will appear at the beginning of each line.
663 Arguments BEG and END specify the beginning and end of the
664 region."
665 (if mark-active
666 (save-excursion
667 (let ((endpos end))
668 ; Ensure that there is a leading blank line
669 (goto-char beg)
670 (while (not (looking-back "\n\n" 2))
671 (insert "\n")
672 (setq endpos (+ 1 endpos)))
673 ; Insert blockquote characters
674 (move-to-left-margin)
675 (while (< (point-at-bol) endpos)
676 (insert prefix)
677 (setq endpos (+ (length prefix) endpos))
678 (forward-line))
679 ; Move back before any blank lines at the end
680 (goto-char endpos)
681 (while (looking-back "\n" 1)
682 (backward-char))
683 ; Ensure one blank line at the end
684 (while (not (looking-at "\n\n"))
685 (insert "\n")
686 (backward-char))))))
688 (defun markdown-blockquote-region (beg end)
689 "Blockquote the region.
690 Arguments BEG and END specify the beginning and end of the region."
691 (interactive "*r")
692 (markdown-block-region beg end "> "))
694 (defun markdown-insert-pre ()
695 "Start a preformatted section (or apply to the region).
696 If Transient Mark mode is on and a region is active, it is marked
697 as preformatted text."
698 (interactive)
699 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
700 (markdown-pre-region (region-beginning) (region-end))
701 (insert " ")))
703 (defun markdown-pre-region (beg end)
704 "Format the region as preformatted text.
705 Arguments BEG and END specify the beginning and end of the region."
706 (interactive "*r")
707 (markdown-block-region beg end " "))
712 ;;; Keymap ====================================================================
714 (defvar markdown-mode-map
715 (let ((markdown-mode-map (make-keymap)))
716 ;; Element insertion
717 (define-key markdown-mode-map "\C-c\C-al" 'markdown-insert-link)
718 (define-key markdown-mode-map "\C-c\C-aw" 'markdown-insert-wiki-link)
719 (define-key markdown-mode-map "\C-c\C-ii" 'markdown-insert-image)
720 (define-key markdown-mode-map "\C-c\C-t1" 'markdown-insert-header-1)
721 (define-key markdown-mode-map "\C-c\C-t2" 'markdown-insert-header-2)
722 (define-key markdown-mode-map "\C-c\C-t3" 'markdown-insert-header-3)
723 (define-key markdown-mode-map "\C-c\C-t4" 'markdown-insert-header-4)
724 (define-key markdown-mode-map "\C-c\C-t5" 'markdown-insert-header-5)
725 (define-key markdown-mode-map "\C-c\C-pb" 'markdown-insert-bold)
726 (define-key markdown-mode-map "\C-c\C-ss" 'markdown-insert-bold)
727 (define-key markdown-mode-map "\C-c\C-pi" 'markdown-insert-italic)
728 (define-key markdown-mode-map "\C-c\C-se" 'markdown-insert-italic)
729 (define-key markdown-mode-map "\C-c\C-pf" 'markdown-insert-code)
730 (define-key markdown-mode-map "\C-c\C-sc" 'markdown-insert-code)
731 (define-key markdown-mode-map "\C-c\C-sb" 'markdown-insert-blockquote)
732 (define-key markdown-mode-map "\C-c\C-s\C-b" 'markdown-blockquote-region)
733 (define-key markdown-mode-map "\C-c\C-sp" 'markdown-insert-pre)
734 (define-key markdown-mode-map "\C-c\C-s\C-p" 'markdown-pre-region)
735 (define-key markdown-mode-map "\C-c-" 'markdown-insert-hr)
736 (define-key markdown-mode-map "\C-c\C-tt" 'markdown-insert-title)
737 (define-key markdown-mode-map "\C-c\C-ts" 'markdown-insert-section)
738 ;; Visibility cycling
739 (define-key markdown-mode-map (kbd "<tab>") 'markdown-cycle)
740 (define-key markdown-mode-map (kbd "<S-iso-lefttab>") 'markdown-shifttab)
741 ;; Markdown functions
742 (define-key markdown-mode-map "\C-c\C-cm" 'markdown)
743 (define-key markdown-mode-map "\C-c\C-cp" 'markdown-preview)
744 ;; References
745 (define-key markdown-mode-map "\C-c\C-cc" 'markdown-check-refs)
746 markdown-mode-map)
747 "Keymap for Markdown major mode.")
749 ;;; Menu ==================================================================
751 (easy-menu-define markdown-mode-menu markdown-mode-map
752 "Menu for Markdown mode"
753 '("Markdown"
754 ("Show/Hide"
755 ["Cycle visibility" markdown-cycle (outline-on-heading-p)]
756 ["Cycle global visibility" markdown-shifttab])
757 "---"
758 ["Compile" markdown]
759 ["Preview" markdown-preview]
760 "---"
761 ("Headers (setext)"
762 ["Insert Title" markdown-insert-title]
763 ["Insert Section" markdown-insert-section])
764 ("Headers (atx)"
765 ["First level" markdown-insert-header-1]
766 ["Second level" markdown-insert-header-2]
767 ["Third level" markdown-insert-header-3]
768 ["Fourth level" markdown-insert-header-4]
769 ["Fifth level" markdown-insert-header-5])
770 "---"
771 ["Bold" markdown-insert-bold]
772 ["Italic" markdown-insert-italic]
773 ["Blockquote" markdown-insert-blockquote]
774 ["Preformatted" markdown-insert-pre]
775 ["Code" markdown-insert-code]
776 "---"
777 ["Insert inline link" markdown-insert-link]
778 ["Insert image" markdown-insert-image]
779 ["Insert horizontal rule" markdown-insert-hr]
780 "---"
781 ["Check references" markdown-check-refs]
782 "---"
783 ["Version" markdown-show-version]
788 ;;; References ================================================================
790 ;;; Undefined reference checking code by Dmitry Dzhus <mail@sphinx.net.ru>.
792 (defconst markdown-refcheck-buffer
793 "*Undefined references for %BUFFER%*"
794 "Pattern for name of buffer for listing undefined references.
795 The string %BUFFER% will be replaced by the corresponding
796 `markdown-mode' buffer name.")
798 (defun markdown-has-reference-definition (reference)
799 "Find out whether Markdown REFERENCE is defined.
801 REFERENCE should include the square brackets, like [this]."
802 (let ((reference (downcase reference)))
803 (save-excursion
804 (goto-char (point-min))
805 (catch 'found
806 (while (re-search-forward markdown-regex-reference-definition nil t)
807 (when (string= reference (downcase (match-string-no-properties 1)))
808 (throw 'found t)))))))
810 (defun markdown-get-undefined-refs ()
811 "Return a list of undefined Markdown references.
813 Result is an alist of pairs (reference . occurencies), where
814 occurencies is itself another alist of pairs (label .
815 line-number).
817 For example, an alist corresponding to [Nice editor][Emacs] at line 12,
818 \[GNU Emacs][Emacs] at line 45 and [manual][elisp] at line 127 is
819 \((\"[emacs]\" (\"[Nice editor]\" . 12) (\"[GNU Emacs]\" . 45)) (\"[elisp]\" (\"[manual]\" . 127)))."
820 (let ((missing))
821 (save-excursion
822 (goto-char (point-min))
823 (while
824 (re-search-forward markdown-regex-link-reference nil t)
825 (let* ((label (match-string-no-properties 1))
826 (reference (match-string-no-properties 2))
827 (target (downcase (if (string= reference "[]") label reference))))
828 (unless (markdown-has-reference-definition target)
829 (let ((entry (assoc target missing)))
830 (if (not entry)
831 (add-to-list 'missing (cons target
832 (list (cons label (markdown-line-number-at-pos)))) t)
833 (setcdr entry
834 (append (cdr entry) (list (cons label (markdown-line-number-at-pos))))))))))
835 missing)))
837 (defun markdown-add-missing-ref-definition (ref buffer &optional recheck)
838 "Add blank REF definition to the end of BUFFER.
840 REF is a Markdown reference in square brackets, like \"[lisp-history]\".
842 When RECHECK is non-nil, BUFFER gets rechecked for undefined
843 references so that REF disappears from the list of those links."
844 (with-current-buffer buffer
845 (when (not (eq major-mode 'markdown-mode))
846 (error "Not available in current mdoe"))
847 (goto-char (point-max))
848 (indent-new-comment-line)
849 (insert (concat ref ": ")))
850 (switch-to-buffer-other-window buffer)
851 (goto-char (point-max))
852 (when recheck
853 (markdown-check-refs t)))
855 ;; Button which adds an empty Markdown reference definition to the end
856 ;; of buffer specified as its 'target-buffer property. Reference name
857 ;; is button's label
858 (when (>= emacs-major-version 22)
859 (define-button-type 'markdown-ref-button
860 'help-echo "Push to create an empty reference definition"
861 'face 'bold
862 'action (lambda (b)
863 (markdown-add-missing-ref-definition
864 (button-label b) (button-get b 'target-buffer) t))))
866 ;; Button jumping to line in buffer specified as its 'target-buffer
867 ;; property. Line number is button's 'line property.
868 (when (>= emacs-major-version 22)
869 (define-button-type 'goto-line-button
870 'help-echo "Push to go to this line"
871 'face 'italic
872 'action (lambda (b)
873 (message (button-get b 'buffer))
874 (switch-to-buffer-other-window (button-get b 'target-buffer))
875 (goto-line (button-get b 'target-line)))))
877 (defun markdown-check-refs (&optional silent)
878 "Show all undefined Markdown references in current `markdown-mode' buffer.
880 If SILENT is non-nil, do not message anything when no undefined
881 references found.
883 Links which have empty reference definitions are considered to be
884 defined."
885 (interactive "P")
886 (when (not (eq major-mode 'markdown-mode))
887 (error "Not available in current mode"))
888 (let ((oldbuf (current-buffer))
889 (refs (markdown-get-undefined-refs))
890 (refbuf (get-buffer-create (replace-regexp-in-string
891 "%BUFFER%" (buffer-name)
892 markdown-refcheck-buffer t))))
893 (if (null refs)
894 (progn
895 (when (not silent)
896 (message "No undefined references found"))
897 (kill-buffer refbuf))
898 (with-current-buffer refbuf
899 (when view-mode
900 (View-exit-and-edit))
901 (erase-buffer)
902 (insert "Following references lack definitions:")
903 (newline 2)
904 (dolist (ref refs)
905 (let ((button-label (format "%s" (car ref))))
906 (if (>= emacs-major-version 22)
907 ;; Create a reference button in Emacs 22
908 (insert-text-button button-label
909 :type 'markdown-ref-button
910 'target-buffer oldbuf)
911 ;; Insert reference as text in Emacs < 22
912 (insert button-label)))
913 (insert " (")
914 (dolist (occurency (cdr ref))
915 (let ((line (cdr occurency)))
916 (if (>= emacs-major-version 22)
917 ;; Create a line number button in Emacs 22
918 (insert-button (number-to-string line)
919 :type 'goto-line-button
920 'target-buffer oldbuf
921 'target-line line)
922 ;; Insert line number as text in Emacs < 22
923 (insert (number-to-string line)))
924 (insert " "))) (delete-backward-char 1)
925 (insert ")")
926 (newline))
927 (view-buffer-other-window refbuf)
928 (goto-line 4)))))
931 ;;; Outline ===================================================================
933 ;; The following visibility cycling code was taken from org-mode
934 ;; by Carsten Dominik and adapted for markdown-mode.
936 (defvar markdown-cycle-global-status 1)
937 (defvar markdown-cycle-subtree-status nil)
939 ;; Based on org-end-of-subtree from org.el
940 (defun markdown-end-of-subtree (&optional invisible-OK)
941 "Move to the end of the current subtree.
942 Only visible heading lines are considered, unless INVISIBLE-OK is
943 non-nil."
944 (outline-back-to-heading invisible-OK)
945 (let ((first t)
946 (level (funcall outline-level)))
947 (while (and (not (eobp))
948 (or first (> (funcall outline-level) level)))
949 (setq first nil)
950 (outline-next-heading))
951 (if (memq (preceding-char) '(?\n ?\^M))
952 (progn
953 ;; Go to end of line before heading
954 (forward-char -1)
955 (if (memq (preceding-char) '(?\n ?\^M))
956 ;; leave blank line before heading
957 (forward-char -1)))))
958 (point))
960 ;; Based on org-cycle from org.el.
961 (defun markdown-cycle (&optional arg)
962 "Visibility cycling for Markdown mode.
963 If ARG is t, perform global visibility cycling. If the point is
964 at an atx-style header, cycle visibility of the corresponding
965 subtree. Otherwise, insert a tab using `indent-relative'."
966 (interactive "P")
967 (cond
968 ((eq arg t) ;; Global cycling
969 (cond
970 ((and (eq last-command this-command)
971 (eq markdown-cycle-global-status 2))
972 ;; Move from overview to contents
973 (hide-sublevels 1)
974 (message "CONTENTS")
975 (setq markdown-cycle-global-status 3))
977 ((and (eq last-command this-command)
978 (eq markdown-cycle-global-status 3))
979 ;; Move from contents to all
980 (show-all)
981 (message "SHOW ALL")
982 (setq markdown-cycle-global-status 1))
985 ;; Defaults to overview
986 (hide-body)
987 (message "OVERVIEW")
988 (setq markdown-cycle-global-status 2))))
990 ((save-excursion (beginning-of-line 1) (looking-at outline-regexp))
991 ;; At a heading: rotate between three different views
992 (outline-back-to-heading)
993 (let ((goal-column 0) eoh eol eos)
994 ;; Determine boundaries
995 (save-excursion
996 (outline-back-to-heading)
997 (save-excursion
998 (beginning-of-line 2)
999 (while (and (not (eobp)) ;; this is like `next-line'
1000 (get-char-property (1- (point)) 'invisible))
1001 (beginning-of-line 2)) (setq eol (point)))
1002 (outline-end-of-heading) (setq eoh (point))
1003 (markdown-end-of-subtree t)
1004 (skip-chars-forward " \t\n")
1005 (beginning-of-line 1) ; in case this is an item
1006 (setq eos (1- (point))))
1007 ;; Find out what to do next and set `this-command'
1008 (cond
1009 ((= eos eoh)
1010 ;; Nothing is hidden behind this heading
1011 (message "EMPTY ENTRY")
1012 (setq markdown-cycle-subtree-status nil))
1013 ((>= eol eos)
1014 ;; Entire subtree is hidden in one line: open it
1015 (show-entry)
1016 (show-children)
1017 (message "CHILDREN")
1018 (setq markdown-cycle-subtree-status 'children))
1019 ((and (eq last-command this-command)
1020 (eq markdown-cycle-subtree-status 'children))
1021 ;; We just showed the children, now show everything.
1022 (show-subtree)
1023 (message "SUBTREE")
1024 (setq markdown-cycle-subtree-status 'subtree))
1026 ;; Default action: hide the subtree.
1027 (hide-subtree)
1028 (message "FOLDED")
1029 (setq markdown-cycle-subtree-status 'folded)))))
1032 (message "TAB")
1033 (indent-relative))))
1035 ;; Based on org-shifttab from org.el.
1036 (defun markdown-shifttab ()
1037 "Global visibility cycling.
1038 Calls `markdown-cycle' with argument t."
1039 (interactive)
1040 (markdown-cycle t))
1042 ;;; Commands ==================================================================
1044 (defun markdown ()
1045 "Run markdown on the current buffer and preview the output in another buffer."
1046 (interactive)
1047 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
1048 (shell-command-on-region (region-beginning) (region-end) markdown-command
1049 "*markdown-output*" nil)
1050 (shell-command-on-region (point-min) (point-max) markdown-command
1051 "*markdown-output*" nil)))
1053 (defun markdown-preview ()
1054 "Run markdown on the current buffer and preview the output in a browser."
1055 (interactive)
1056 (markdown)
1057 (browse-url-of-buffer "*markdown-output*"))
1060 ;;; Miscellaneous =============================================================
1062 (defun markdown-line-number-at-pos (&optional pos)
1063 "Return (narrowed) buffer line number at position POS.
1064 If POS is nil, use current buffer location.
1065 This is an exact copy of `line-number-at-pos' for use in emacs21."
1066 (let ((opoint (or pos (point))) start)
1067 (save-excursion
1068 (goto-char (point-min))
1069 (setq start (point))
1070 (goto-char opoint)
1071 (forward-line 0)
1072 (1+ (count-lines start (point))))))
1076 ;;; Mode definition ==========================================================
1078 (defun markdown-show-version ()
1079 "Show the version number in the minibuffer."
1080 (interactive)
1081 (message "markdown-mode, version %s" markdown-mode-version))
1083 (define-derived-mode markdown-mode text-mode "Markdown"
1084 "Major mode for editing Markdown files."
1085 ;; Font lock.
1086 (set (make-local-variable 'font-lock-defaults)
1087 '(markdown-mode-font-lock-keywords))
1088 (set (make-local-variable 'font-lock-multiline) t)
1089 ;; For menu support in XEmacs
1090 (easy-menu-add markdown-mode-menu markdown-mode-map)
1091 ;; Make filling work with lists
1092 (set (make-local-variable 'paragraph-start)
1093 "\f\\|[ \t]*$\\|^[ \t]*[*+-] \\|^[ \t*][0-9]+\\. ")
1094 ;; Outline mode
1095 (make-local-variable 'outline-regexp)
1096 (setq outline-regexp "#+")
1097 ;; Cause use of ellipses for invisible text.
1098 (add-to-invisibility-spec '(outline . t)))
1100 ;(add-to-list 'auto-mode-alist '("\\.text$" . markdown-mode))
1102 (provide 'markdown-mode)
1104 ;;; markdown-mode.el ends here