* Added support for equals and dash style headings.
[markdown-mode/intrigeri.git] / markdown-mode.el
blobe9dc703774a0398ac42e6af559914454bcea8732
1 ;;; markdown-mode.el --- Major mode to edit Markdown files in Emacs
2 ;;
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
8 ;;
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)
14 ;; any later version.
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.
25 ;; Supported Emacsen:
26 ;; ==================
27 ;; This mode has only been tested on Emacs 22.0. Please let me know
28 ;; if there are problems on other versions.
30 ;; Installation:
31 ;; =============
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
36 ;; files.
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.
45 ;; Description:
46 ;; ============
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.
52 ;; TODO:
53 ;; =====
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
69 "Markdown mode."
70 :prefix "markdown-"
71 :group 'languages)
73 (defcustom markdown-command "markdown"
74 "Command to run markdown."
75 :group 'markdown
76 :type 'string)
78 (defcustom markdown-hr-length 5
79 "Length of horizonal rules."
80 :group 'markdown
81 :type 'integer)
83 (defcustom markdown-bold-underscore nil
84 "Use two underscores for bold instead of two asterisks."
85 :group 'markdown
86 :type 'boolean)
88 (defcustom markdown-italic-underscore nil
89 "Use underscores for italic instead of asterisks."
90 :group 'markdown
91 :type 'boolean)
94 ;;; Regular expressions =======================================================
96 ;; Links
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
109 (list
110 ;; Latex/itex
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
120 ;; Blockquotes
121 (cons "^>.*$" 'font-lock-comment-face) ; > blockquote
122 ;; Bold
123 (cons "[^\\]?\\*\\*.+?\\*\\*" 'font-lock-type-face) ; **bold**
124 (cons "[^\\]?__.+?__" 'font-lock-type-face) ; __bold__
125 ;; Italic
126 (cons "[^\\]?\\*.+?\\*" 'font-lock-variable-name-face) ; *italic*
127 (cons "[^\\]?_.+?_" 'font-lock-variable-name-face) ; _italic_
128 ;; Lists
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)
136 ;; Links
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))
143 ;; Wiki links
144 ; (cons "\\[\\[\\w+\\]\\]" 'font-lock-string-face) ; Standard wiki link
145 (cons "\\[\\[.+\\]\\]" 'font-lock-string-face)
146 ;; Code
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)))
161 (kill-region a b)
162 (insert s1)
163 (yank)
164 (insert s2))
165 (insert s1 s2)))
167 (defun markdown-insert-hr ()
168 "Insert a horizonal rule."
169 (interactive)
170 (let (hr)
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 *
174 (insert hr)))
176 (defun markdown-insert-bold ()
177 "Make the active region bold or insert an empty bold word."
178 (interactive)
179 (if markdown-bold-underscore
180 (wrap-or-insert "__" "__")
181 (wrap-or-insert "**" "**"))
182 (backward-char 2))
184 (defun markdown-insert-italic ()
185 "Make the active region italic or insert an empty italic word."
186 (interactive)
187 (if markdown-italic-underscore
188 (wrap-or-insert "_" "_")
189 (wrap-or-insert "*" "*"))
190 (backward-char 1))
192 (defun markdown-insert-code ()
193 "Format the active region as inline code or insert an empty inline code
194 fragment."
195 (interactive)
196 (wrap-or-insert "`" "`")
197 (backward-char 1))
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."
202 (interactive)
203 (wrap-or-insert "[" "]")
204 (insert "()")
205 (backward-char 1))
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."
210 (interactive)
211 (wrap-or-insert "![" "]")
212 (insert "()")
213 (backward-char 1))
215 (defun markdown-insert-header-1 ()
216 "Creates a level 1 header"
217 (interactive)
218 (markdown-insert-header 1))
220 (defun markdown-insert-header-2 ()
221 "Creates a level 2 header"
222 (interactive)
223 (markdown-insert-header 2))
225 (defun markdown-insert-header-3 ()
226 "Creates a level 3 header"
227 (interactive)
228 (markdown-insert-header 3))
230 (defun markdown-insert-header-4 ()
231 "Creates a level 4 header"
232 (interactive)
233 (markdown-insert-header 4))
235 (defun markdown-insert-header-5 ()
236 "Creates a level 5 header"
237 (interactive)
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
242 header text."
243 (interactive "p")
244 (unless n ; Test to see if n is defined
245 (setq n 1)) ; Default to level 1 header
246 (let (hdr)
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
257 insert a title."
258 (interactive)
259 (if (and transient-mark-mode mark-active)
260 (let ((a (region-beginning))
261 (b (region-end))
262 (len 0)
263 (hdr))
264 (setq len (- b a))
265 (dotimes (count len hdr)
266 (setq hdr (concat "=" hdr))) ; Build a === title underline
267 (end-of-line)
268 (insert "\n" hdr "\n"))
269 (insert "\n==========\n")
270 (backward-char 12)))
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
275 insert a section."
276 (interactive)
277 (if (and transient-mark-mode mark-active)
278 (let ((a (region-beginning))
279 (b (region-end))
280 (len 0)
281 (hdr))
282 (setq len (- b a))
283 (dotimes (count len hdr)
284 (setq hdr (concat "-" hdr))) ; Build a --- section underline
285 (end-of-line)
286 (insert "\n" hdr "\n"))
287 (insert "\n----------\n")
288 (backward-char 12)))
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."
293 (interactive)
294 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
295 (blockquote-region)
296 (insert "> ")))
299 ;;; Keymap ====================================================================
301 (defvar markdown-mode-map
302 (let ((markdown-mode-map (make-keymap)))
303 ;; Element insertion
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)
324 markdown-mode-map)
325 "Keymap for Markdown major mode")
328 ;;; Markdown ==================================================================
330 (defun markdown ()
331 "Run markdown on the current buffer and preview the output in another buffer."
332 (interactive)
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."
341 (interactive)
342 (markdown)
343 (browse-url-of-buffer "*markdown-output*"))
346 ;;; Utilities =================================================================
348 (defun markdown-show-version ()
349 "Show the version number in the minibuffer."
350 (interactive)
351 (message "markdown-mode, version %s" markdown-mode-version))
353 (defun blockquote-region ()
354 "Blockquote an entire region."
355 (interactive)
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."
364 ;; Font lock.
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)
373 ;;; Change log
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.
392 ;; * Revision 1.2.
394 ;; 2007-05-24 Jason Blevins <jrblevin@sdf.lonestar.org>
395 ;; * Initial revision.
396 ;; * Basic syntax highlighting support.
397 ;; * Revision 1.1.
399 ;;; markdown-mode.el ends here