1 ;;; markdown-mode.el --- Major mode to edit Markdown files in Emacs
3 ;; Author: Jason Blevins <jrblevin@sdf.lonestar.org>
4 ;; Maintainer: Jason Blevins <jrblevin@sdf.lonestar.org>
5 ;; Created: May 24, 2007
6 ;; $Id: markdown-mode.el,v 1.3 2007/06/05 03:29:43 jrblevin Exp $
7 ;; Keywords: Markdown major mode
9 ;; Copyright (C) 2007 Jason Blevins
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with this program; if not, write to the Free Software
23 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 ;; This mode has only been tested on Emacs 22.0. Please let me know
28 ;; if there are problems on other versions.
32 ;; Add the following lines to your .emacs file to associate
33 ;; markdown-mode with .mdml files. There doesn't seem to be
34 ;; a consensus on an official file extension so you can change
35 ;; this to .text, .md, .mdt, or whatever you call your markdown
38 ;; (autoload 'markdown-mode "markdown-mode.el"
39 ;; "Major mode for editing Markdown files" t)
40 ;; (setq auto-mode-alist
41 ;; (cons '("\\.mdml$" . markdown-mode) auto-mode-alist))
43 ;; Make sure to place this file somewhere in the load-path.
47 ;; This mode provides basic syntax highlighting, element insertion
48 ;; commands, and preview commands for Markdown files. The latest version
49 ;; should always be available from
50 ;; http://jrblevin.freeshell.org/software/markdown-mode.
54 ;; * Recognize inline HTML.
55 ;; * Bold at the beginning of a line is mistaken to be a list item.
56 ;; * itex font lock support:
57 ;; + Equation references: (eq:reference) or \eqref{reference}.
58 ;; + Separate font locking for \label{} elements in side \[ \] equations.
60 (defconst markdown-mode-version
"$Revision: 1.3 $")
62 ;; A hook for users to run their own code when the mode is loaded.
63 (defvar markdown-mode-hook nil
)
66 ;;; Customizable variables ====================================================
68 (defgroup markdown nil
73 (defcustom markdown-command
"markdown"
74 "Command to run markdown."
78 (defcustom markdown-hr-length
5
79 "Length of horizonal rules."
83 (defcustom markdown-bold-underscore nil
84 "Use two underscores for bold instead of two asterisks."
88 (defcustom markdown-italic-underscore nil
89 "Use underscores for italic instead of asterisks."
94 ;;; Regular expressions =======================================================
97 (defconst regex-link-inline
"\\(!?\\[.+?\\]\\)\\((.*)\\)"
98 "Regular expression for a [text](file) or an image link ![text](file)")
99 (defconst regex-link-reference
"\\(!?\\[.+?\\]\\)[ ]?\\(\\[.*?\\]\\)"
100 "Regular expression for a reference link [text][id]")
101 (defconst regex-reference-definition
102 "^\s*\\(\\[.+?\\]\\):\s*\\([^\s\n]+\\).*$"
103 "Regular expression for a link definition [id]: ...")
106 ;;; Font lock =================================================================
108 (defconst markdown-mode-font-lock-keywords
111 ; (cons "\\\\\\[[^$]+\\\\\\]" 'font-lock-string-face)
112 ; (cons "\\$\\$[^$]+\\$\\$" 'font-lock-string-face)
113 ; (cons "\\$[^$]+\\$" 'font-lock-string-face)
114 ;; Headers and (Horizontal Rules)
115 (cons ".*\n?===*" 'font-lock-function-name-face
) ; === headers
116 (cons ".*\n?---*" 'font-lock-function-name-face
) ; --- headers
117 (cons "^#+ .*$" 'font-lock-function-name-face
) ; ### Headers
118 (cons "^\\*[\\*\s]*$" 'font-lock-function-name-face
) ; * * * style HRs
119 (cons "^-[-\s]*$" 'font-lock-function-name-face
) ; - - - style HRs
121 (cons "^>.*$" 'font-lock-comment-face
) ; > blockquote
123 (cons "[^\\]?\\*\\*.+?\\*\\*" 'font-lock-type-face
) ; **bold**
124 (cons "[^\\]?__.+?__" 'font-lock-type-face
) ; __bold__
126 (cons "[^\\]?\\*.+?\\*" 'font-lock-variable-name-face
) ; *italic*
127 (cons "[^\\]?_.+?_" 'font-lock-variable-name-face
) ; _italic_
129 (cons "^[0-9]+\\." 'font-lock-variable-name-face
) ; Numbered list
130 (cons "^\\*" 'font-lock-variable-name-face
) ; Level 1 (no indent)
131 (cons "^\\+" 'font-lock-variable-name-face
) ; Level 1 (no indent)
132 (cons "^\\-" 'font-lock-variable-name-face
) ; Level 1 (no indent)
133 (cons "^ [ ]*\\*" 'font-lock-variable-name-face
) ; Level 2 (two or more)
134 (cons "^ [ ]*\\+" 'font-lock-variable-name-face
) ; Level 2 (two or more)
135 (cons "^ [ ]*\\-" 'font-lock-variable-name-face
) ; Level 2 (two or more)
137 (cons regex-link-inline
'(1 'font-lock-string-face t
))
138 (cons regex-link-inline
'(2 'font-lock-constant-face t
))
139 (cons regex-link-reference
'(1 'font-lock-string-face t
))
140 (cons regex-link-reference
'(2 'font-lock-comment-face t
))
141 (cons regex-reference-definition
'(1 'font-lock-comment-face t
))
142 (cons regex-reference-definition
'(2 'font-lock-constant-face t
))
144 ; (cons "\\[\\[\\w+\\]\\]" 'font-lock-string-face) ; Standard wiki link
145 (cons "\\[\\[.+\\]\\]" 'font-lock-string-face
)
147 (cons "``.+?``" 'font-lock-constant-face
) ; ``inline code``
148 (cons "`.+?`" 'font-lock-constant-face
) ; `inline code`
149 (cons "^ .*$" 'font-lock-constant-face
) ; code block
151 "Syntax highlighting for Markdown files.")
154 ;;; Element Insertion ==========================================================
156 (defun wrap-or-insert (s1 s2
)
157 "Insert the strings s1 and s2 around the current region or just insert them
158 if there is no region selected."
159 (if (and transient-mark-mode mark-active
)
160 (let ((a (region-beginning)) (b (region-end)))
167 (defun markdown-insert-hr ()
168 "Insert a horizonal rule."
171 (dotimes (count (- markdown-hr-length
1) hr
) ; Count to n - 1
172 (setq hr
(concat "* " hr
))) ; Build HR string
173 (setq hr
(concat hr
"*\n")) ; Add the n-th *
176 (defun markdown-insert-bold ()
177 "Make the active region bold or insert an empty bold word."
179 (if markdown-bold-underscore
180 (wrap-or-insert "__" "__")
181 (wrap-or-insert "**" "**"))
184 (defun markdown-insert-italic ()
185 "Make the active region italic or insert an empty italic word."
187 (if markdown-italic-underscore
188 (wrap-or-insert "_" "_")
189 (wrap-or-insert "*" "*"))
192 (defun markdown-insert-code ()
193 "Format the active region as inline code or insert an empty inline code
196 (wrap-or-insert "`" "`")
199 (defun markdown-insert-link ()
200 "Creates an empty link of the form [](). If there is an active region,
201 this text will be used for the link text."
203 (wrap-or-insert "[" "]")
207 (defun markdown-insert-image ()
208 "Creates an empty image of the form ![](). If there is an active region,
209 this text will be used for the alternate text for the image."
211 (wrap-or-insert "![" "]")
215 (defun markdown-insert-header-1 ()
216 "Creates a level 1 header"
218 (markdown-insert-header 1))
220 (defun markdown-insert-header-2 ()
221 "Creates a level 2 header"
223 (markdown-insert-header 2))
225 (defun markdown-insert-header-3 ()
226 "Creates a level 3 header"
228 (markdown-insert-header 3))
230 (defun markdown-insert-header-4 ()
231 "Creates a level 4 header"
233 (markdown-insert-header 4))
235 (defun markdown-insert-header-5 ()
236 "Creates a level 5 header"
238 (markdown-insert-header 5))
240 (defun markdown-insert-header (n)
241 "Creates a level n header. If there is an active region, it is used as the
244 (unless n
; Test to see if n is defined
245 (setq n
1)) ; Default to level 1 header
247 (dotimes (count n hdr
)
248 (setq hdr
(concat "#" hdr
))) ; Build a ### header string
249 (setq hdrl
(concat hdr
" "))
250 (setq hdrr
(concat " " hdr
))
251 (wrap-or-insert hdrl hdrr
))
252 (backward-char (+ 1 n
)))
254 (defun markdown-insert-title ()
255 "Use the active region to create an \"equals\" style title or insert
256 a blank title and move the cursor to the required position in order to
259 (if (and transient-mark-mode mark-active
)
260 (let ((a (region-beginning))
265 (dotimes (count len hdr
)
266 (setq hdr
(concat "=" hdr
))) ; Build a === title underline
268 (insert "\n" hdr
"\n"))
269 (insert "\n==========\n")
272 (defun markdown-insert-section ()
273 "Use the active region to create a dashed style section or insert
274 a blank section and move the cursor to the required position in order to
277 (if (and transient-mark-mode mark-active
)
278 (let ((a (region-beginning))
283 (dotimes (count len hdr
)
284 (setq hdr
(concat "-" hdr
))) ; Build a --- section underline
286 (insert "\n" hdr
"\n"))
287 (insert "\n----------\n")
290 (defun markdown-insert-blockquote ()
291 "Start a blank blockquote section unless there is an active region, in
292 which case it is turned into a blockquote region."
294 (if (and (boundp 'transient-mark-mode
) transient-mark-mode mark-active
)
299 ;;; Keymap ====================================================================
301 (defvar markdown-mode-map
302 (let ((markdown-mode-map (make-keymap)))
304 (define-key markdown-mode-map
"\C-c\C-al" 'markdown-insert-link
)
305 (define-key markdown-mode-map
"\C-c\C-ii" 'markdown-insert-image
)
306 (define-key markdown-mode-map
"\C-c\C-t1" 'markdown-insert-header-1
)
307 (define-key markdown-mode-map
"\C-c\C-t2" 'markdown-insert-header-2
)
308 (define-key markdown-mode-map
"\C-c\C-t3" 'markdown-insert-header-3
)
309 (define-key markdown-mode-map
"\C-c\C-t4" 'markdown-insert-header-4
)
310 (define-key markdown-mode-map
"\C-c\C-t5" 'markdown-insert-header-5
)
311 (define-key markdown-mode-map
"\C-c\C-pb" 'markdown-insert-bold
)
312 (define-key markdown-mode-map
"\C-c\C-ss" 'markdown-insert-bold
)
313 (define-key markdown-mode-map
"\C-c\C-pi" 'markdown-insert-italic
)
314 (define-key markdown-mode-map
"\C-c\C-se" 'markdown-insert-italic
)
315 (define-key markdown-mode-map
"\C-c\C-pf" 'markdown-insert-code
)
316 (define-key markdown-mode-map
"\C-c\C-sc" 'markdown-insert-code
)
317 (define-key markdown-mode-map
"\C-c\C-sb" 'markdown-insert-blockquote
)
318 (define-key markdown-mode-map
"\C-c-" 'markdown-insert-hr
)
319 (define-key markdown-mode-map
"\C-c\C-tt" 'markdown-insert-title
)
320 (define-key markdown-mode-map
"\C-c\C-ts" 'markdown-insert-section
)
321 ;; Markdown functions
322 (define-key markdown-mode-map
"\C-c\C-cm" 'markdown
)
323 (define-key markdown-mode-map
"\C-c\C-cp" 'markdown-preview
)
325 "Keymap for Markdown major mode")
328 ;;; Markdown ==================================================================
331 "Run markdown on the current buffer and preview the output in another buffer."
333 (if (and (boundp 'transient-mark-mode
) transient-mark-mode mark-active
)
334 (shell-command-on-region region-beginning region-end markdown-command
335 "*markdown-output*" nil
)
336 (shell-command-on-region (point-min) (point-max) markdown-command
337 "*markdown-output*" nil
)))
339 (defun markdown-preview ()
340 "Run markdown on the current buffer and preview the output in a browser."
343 (browse-url-of-buffer "*markdown-output*"))
346 ;;; Utilities =================================================================
348 (defun markdown-show-version ()
349 "Show the version number in the minibuffer."
351 (message "markdown-mode, version %s" markdown-mode-version
))
353 (defun blockquote-region ()
354 "Blockquote an entire region."
356 (if (and (boundp 'transient-mark-mode
) transient-mark-mode mark-active
)
357 (replace-regexp "^" "> ")))
360 ;; Mode definition ===========================================================
362 (define-derived-mode markdown-mode fundamental-mode
"Markdown"
363 "Major mode for editing Markdown files."
365 (set (make-local-variable 'font-lock-defaults
)
366 '(markdown-mode-font-lock-keywords))
367 (set (make-local-variable 'font-lock-multiline
) t
))
369 ;(add-to-list 'auto-mode-alist '("\\.mdml$" . markdown-mode))
371 (provide 'markdown-mode
)
374 ;; 2007-05-29 Jason Blevins <jrblevin@sdf.lonestar.org>
375 ;; * Added support for equals and dash style headings.
376 ;; * Added markdown-show-version.
377 ;; * Ability to preview markdown output in a buffer (markdown) or
378 ;; in a browser (markdown-preview). Markdown command is customizable.
379 ;; * Made HR length customizable through markdown-hr-length.
380 ;; * Made bold and italic style customizable through markdown-bold-underscore
381 ;; and markdown-italic-underscore.
382 ;; * Made keybindings more like those of html-helper-mode.
383 ;; * Added image insertion (markdown-insert-image).
384 ;; * Font lock for code fragments with double backticks.
385 ;; * Added blockquote-region function and insert-blockquote keybinding.
386 ;; * Don't highlight escaped literals such as \* or \_.
387 ;; * Added header insertion commands for H1-H5 (markdown-insert-header-n).
389 ;; 2007-05-25 Jason Blevins <jrblevin@sdf.lonestar.org>
390 ;; * Added element insertion commands and keys for links, horizontal rules,
391 ;; headers, inline code, and bold and italic text.
394 ;; 2007-05-24 Jason Blevins <jrblevin@sdf.lonestar.org>
395 ;; * Initial revision.
396 ;; * Basic syntax highlighting support.
399 ;;; markdown-mode.el ends here