· 11 years ago · Jun 21, 2015, 08:31 PM
1;;; markdown-mode.el --- Emacs Major mode for Markdown-formatted text files
2
3;; Copyright (C) 2007-2011 Jason R. Blevins <jrblevin@sdf.org>
4;; Copyright (C) 2007, 2009 Edward O'Connor <ted@oconnor.cx>
5;; Copyright (C) 2007 Conal Elliott <conal@conal.net>
6;; Copyright (C) 2008 Greg Bognar <greg_bognar@hms.harvard.edu>
7;; Copyright (C) 2008 Dmitry Dzhus <mail@sphinx.net.ru>
8;; Copyright (C) 2008 Bryan Kyle <bryan.kyle@gmail.com>
9;; Copyright (C) 2008 Ben Voui <intrigeri@boum.org>
10;; Copyright (C) 2009 Ankit Solanki <ankit.solanki@gmail.com>
11;; Copyright (C) 2009 Hilko Bengen <bengen@debian.org>
12;; Copyright (C) 2009 Peter Williams <pezra@barelyenough.org>
13;; Copyright (C) 2010 George Ogata <george.ogata@gmail.com>
14;; Copyright (C) 2011 Eric Merritt <ericbmerritt@gmail.com>
15;; Copyright (C) 2011 Philippe Ivaldi <pivaldi@sfr.fr>
16;; Copyright (C) 2011 Jeremiah Dodds <jeremiah.dodds@gmail.com>
17
18;; Author: Jason R. Blevins <jrblevin@sdf.org>
19;; Maintainer: Jason R. Blevins <jrblevin@sdf.org>
20;; Created: May 24, 2007
21;; Version: 1.8.1
22;; Keywords: Markdown, GitHub Flavored Markdown, itex
23;; URL: http://jblevins.org/projects/markdown-mode/
24
25;; This file is not part of GNU Emacs.
26
27;; This program is free software; you can redistribute it and/or modify
28;; it under the terms of the GNU General Public License as published by
29;; the Free Software Foundation; either version 2, or (at your option)
30;; any later version.
31
32;; This program is distributed in the hope that it will be useful,
33;; but WITHOUT ANY WARRANTY; without even the implied warranty of
34;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35;; GNU General Public License for more details.
36
37;; You should have received a copy of the GNU General Public License
38;; along with this program; if not, write to the Free Software
39;; Foundation, Inc., 51 Franklin Street, Fifth Floor,
40;; Boston, MA 02110-1301, USA.
41
42;;; Commentary:
43
44;; markdown-mode is a major mode for editing [Markdown][]-formatted
45;; text files in GNU Emacs. markdown-mode is free software, licensed
46;; under the GNU GPL.
47;;
48;; [Markdown]: http://daringfireball.net/projects/markdown/
49;;
50;; The latest stable version is markdown-mode 1.8.1, released on August 15, 2011:
51;;
52;; * [markdown-mode.el][]
53;; * [Screenshot][]
54;; * [Release notes][]
55;;
56;; [markdown-mode.el]: http://jblevins.org/projects/markdown-mode/markdown-mode.el
57;; [screenshot]: http://jblevins.org/projects/markdown-mode/screenshots/20110812-001.png
58;; [release notes]: http://jblevins.org/projects/markdown-mode/rev-1-8-1
59;;
60;; markdown-mode is also available in several package managers, including:
61;;
62;; * Debian and Ubuntu Linux: [emacs-goodies-el][]
63;; * RedHat and Fedora Linux: [emacs-goodies][]
64;; * OpenBSD: [textproc/markdown-mode][]
65;; * Arch Linux (AUR): [emacs-markdown-mode-git][]
66;;
67;; [emacs-goodies-el]: http://packages.debian.org/emacs-goodies-el
68;; [emacs-goodies]: https://admin.fedoraproject.org/pkgdb/acls/name/emacs-goodies
69;; [textproc/markdown-mode]: http://pkgsrc.se/textproc/markdown-mode
70;; [emacs-markdown-mode-git]: http://aur.archlinux.org/packages.php?ID=30389
71;;
72;; The latest development version can be downloaded directly
73;; ([markdown-mode.el][devel.el]) or it can be obtained from the
74;; (browsable and clonable) Git repository at
75;; <http://jblevins.org/git/markdown-mode.git>. The entire repository,
76;; including the full project history, can be cloned via the Git protocol
77;; by running
78;;
79;; git clone git://jblevins.org/git/markdown-mode.git
80;;
81;; [devel.el]: http://jblevins.org/git/markdown-mode.git/plain/markdown-mode.el
82
83;;; Dependencies:
84
85;; markdown-mode requires easymenu, a standard package since GNU Emacs
86;; 19 and XEmacs 19, which provides a uniform interface for creating
87;; menus in GNU Emacs and XEmacs.
88
89;;; Installation:
90
91;; Make sure to place `markdown-mode.el` somewhere in the load-path and add
92;; the following lines to your `.emacs` file to associate markdown-mode
93;; with `.text` files:
94;;
95;; (autoload 'markdown-mode "markdown-mode.el"
96;; "Major mode for editing Markdown files" t)
97;; (setq auto-mode-alist
98;; (cons '("\\.text" . markdown-mode) auto-mode-alist))
99;;
100;; There is no consensus on an official file extension so change `.text` to
101;; `.mdwn`, `.md`, `.mdt`, or whatever you call your markdown files.
102
103;;; Customization:
104
105;; Although no configuration is *necessary* there are a few things
106;; that can be customized. The `M-x customize-mode` command
107;; provides an interface to all of the possible customizations:
108;;
109;; * `markdown-command' - the command used to run Markdown (default:
110;; `markdown'). This variable may be customized to pass
111;; command-line options to your Markdown processor of choice, but
112;; this command must accept input from `stdin`. If it does not, a
113;; simple wrapper script can be used to write `stdin` to a file
114;; and then pass that file to your Markdown interpreter. Ideally,
115;; this command will produce an XHTML fragment around which
116;; markdown-mode will wrap a header and footer (which can be
117;; further customized). However, it attempts to detect whether
118;; the command produces standalone XHTML output (via
119;; `markdown-xhtml-standalone-regexp'), in which case no header
120;; and footer content will be added.
121;;
122;; * `markdown-command-needs-filename' - set to non-nil if
123;; `markdown-command' does not accept input from stdin (default: nil).
124;; Instead, it will be passed a filename as the final command-line
125;; option. As a result, you will only be able to run Markdown
126;; from buffers which are visiting a file.
127;;
128;; * `markdown-hr-string' - string to use when inserting horizontal
129;; rules (default: `* * * * *').
130;;
131;; * `markdown-bold-underscore' - set to a non-nil value to use two
132;; underscores for bold instead of two asterisks (default: `nil').
133;;
134;; * `markdown-italic-underscore' - set to a non-nil value to use
135;; underscores for italic instead of asterisks (default: `nil').
136;;
137;; * `markdown-indent-function' - the function to use for automatic
138;; indentation (default: `markdown-indent-line').
139;;
140;; * `markdown-indent-on-enter' - set to a non-nil value to
141;; automatically indent new lines when the enter key is pressed
142;; (default: `t')
143;;
144;; * `markdown-follow-wiki-link-on-enter' - set to a non-nil value
145;; to automatically open a linked document in a new buffer if the
146;; cursor is an wiki link
147;; (default: `t')
148;;
149;; * `markdown-uri-types' - a list of protocols for URIs that
150;; `markdown-mode' should highlight.
151;;
152;; * `markdown-enable-math' - syntax highlighting for
153;; LaTeX fragments (default: `nil').
154;;
155;; * `markdown-css-path' - CSS file to link to in XHTML output.
156;;
157;; * `markdown-xhtml-header-content' - additional content to include
158;; in the XHTML `<head>` block.
159;;
160;; * `markdown-xhtml-standalone-regexp' - a regular expression which
161;; indicates whether the output of `markdown-command' is standalone
162;; XHTML (default: `^\\(\<\?xml\\|\<!DOCTYPE\\|\<html\\)`). If
163;; this is not matched, we assume this output is a fragment and add
164;; our own header and footer.
165;;
166;; Additionally, the faces used for syntax highlighting can be modified to
167;; your liking by issuing `M-x customize-group RET markdown-faces`
168;; or by using the "Markdown Faces" link at the bottom of the mode
169;; customization screen.
170
171;;; Usage:
172
173;; Keybindings are grouped by prefixes based on their function. For
174;; example, commands dealing with headers begin with `C-c C-t`. The
175;; primary commands in each group will are described below. You can
176;; obtain a list of all keybindings by pressing `C-c C-h`.
177;;
178;; * Anchors: `C-c C-a`
179;;
180;; `C-c C-a l` inserts inline links of the form `[text](url)`. If
181;; there is an active region, text in the region is used for the
182;; link text. `C-c C-a w` acts similarly for wiki links of the
183;; form `[[WikiLink]]`.
184;;
185;; * Commands: `C-c C-c`
186;;
187;; `C-c C-c m` will run Markdown on the current buffer and preview
188;; the output in another buffer while `C-c C-c p` runs Markdown on
189;; the current buffer and previews the output in a browser.
190;; `C-c C-c e` will run Markdown on the current buffer and save
191;; the result in the file `basename.html`, where `basename` is the
192;; name of the Markdown file with the extension removed. **This
193;; file will be overwritten without notice.** Press `C-c C-c v`
194;; to view the exported file in a browser.
195;;
196;; `C-c C-c c` will check for undefined references. If there are
197;; any, a small buffer will open with a list of undefined
198;; references and the line numbers on which they appear. In Emacs
199;; 22 and greater, selecting a reference from this list and
200;; pressing `RET` will insert an empty reference definition at the
201;; end of the buffer. Similarly, selecting the line number will
202;; jump to the corresponding line.
203;;
204;; * Images: `C-c C-i`
205;;
206;; `C-c C-i i` inserts an image, using the active region (if any)
207;; as the alt text.
208;;
209;; * Physical styles: `C-c C-p`
210;;
211;; These commands all act on text in the active region, if any,
212;; and insert empty markup fragments otherwise. `C-c C-p b` makes
213;; the selected text bold, `C-c C-p f` formats the region as
214;; fixed-width text, and `C-c C-p i` is used for italic text.
215;;
216;; * Logical styles: `C-c C-s`
217;;
218;; These commands all act on text in the active region, if any,
219;; and insert empty markup fragments otherwise. Logical styles
220;; include blockquote (`C-c C-s b`), preformatted (`C-c C-s p`),
221;; code (`C-c C-s c`), emphasis (`C-c C-s e`), and strong
222;; (`C-c C-s s`).
223;;
224;; * Headers: `C-c C-t`
225;;
226;; All header commands use text in the active region, if any, as
227;; the header text. To insert an atx or hash style level-n
228;; header, press `C-c C-t n` where n is between 1 and 6. For a
229;; top-level setext or underline style header press `C-c C-t t`
230;; (mnemonic: title) and for a second-level underline-style header
231;; press `C-c C-t s` (mnemonic: section).
232;;
233;; * Other elements:
234;;
235;; `C-c -` inserts a horizontal rule.
236;;
237;; * Wiki-Link Navigation:
238;;
239;; Use `M-p` and `M-n` to quickly jump to the previous and next
240;; wiki links, respectively.
241;;
242;; * Outline Navigation:
243;;
244;; Navigation between headings is possible using `outline-mode'.
245;; Use `C-M-n` and `C-M-p` to move between the next and previous
246;; visible headings. Similarly, `C-M-f` and `C-M-b` move to the
247;; next and previous visible headings at the same level as the one
248;; at the point. Finally, `C-M-u` will move up to a lower-level
249;; (more inclusive) visible heading.
250;;
251;; Many of the commands described above behave differently depending on
252;; whether Transient Mark mode is enabled or not. When it makes sense,
253;; if Transient Mark mode is on and a region is active, the command
254;; applies to the text in the region (e.g., `C-c C-p b` makes the region
255;; bold). For users who prefer to work outside of Transient Mark mode,
256;; in Emacs 22 it can be enabled temporarily by pressing `C-SPC C-SPC`.
257;;
258;; When applicable, commands that specifically act on the region even
259;; outside of Transient Mark mode have the same keybinding as the with
260;; the exception of an additional `C-` prefix. For example,
261;; `markdown-insert-blockquote' is bound to `C-c C-s b` and only acts on
262;; the region in Transient Mark mode while `markdown-blockquote-region'
263;; is bound to `C-c C-s C-b` and always applies to the region (when
264;; nonempty).
265;;
266;; markdown-mode attempts to be flexible in how it handles
267;; indentation. When you press `TAB` repeatedly, the point will cycle
268;; through several possible indentation levels corresponding to things
269;; you might have in mind when you press `RET` at the end of a line or
270;; `TAB`. For example, you may want to start a new list item,
271;; continue a list item with hanging indentation, indent for a nested
272;; pre block, and so on.
273;;
274;; markdown-mode supports outline-minor-mode as well as org-mode-style
275;; visibility cycling for atx- or hash-style headers. There are two
276;; types of visibility cycling: Pressing `S-TAB` cycles globally between
277;; the table of contents view (headers only), outline view (top-level
278;; headers only), and the full document view. Pressing `TAB` while the
279;; point is at a header will cycle through levels of visibility for the
280;; subtree: completely folded, visible children, and fully visible.
281;; Note that mixing hash and underline style headers will give undesired
282;; results.
283
284;;; Extensions:
285
286;; Besides supporting the basic Markdown syntax, markdown-mode also
287;; includes syntax highlighting for `[[Wiki Links]]` by default. Wiki
288;; links may be followed automatically by hitting the enter key when
289;; your curser is on a wiki link or by hitting `C-c C-f`. The
290;; autofollowing on enter key may be controlled with the
291;; `markdown-follow-wiki-link-on-enter' customization. Use `M-p` and
292;; `M-n` to quickly jump to the previous and next wiki links,
293;; respectively. Aliased or piped wiki links of the form
294;; `[[PageName|link text]]` are also supported.
295;;
296;; [SmartyPants][] support is possible by customizing `markdown-command'.
297;; If you install `SmartyPants.pl` at, say, `/usr/local/bin/smartypants`,
298;; then you can set `markdown-command' to `"markdown | smartypants"`.
299;; You can do this either by using `M-x customize-group markdown`
300;; or by placing the following in your `.emacs` file:
301;;
302;; (defun markdown-custom ()
303;; "markdown-mode-hook"
304;; (setq markdown-command "markdown | smartypants"))
305;; (add-hook 'markdown-mode-hook '(lambda() (markdown-custom)))
306;;
307;; [SmartyPants]: http://daringfireball.net/projects/smartypants/
308;;
309;; Experimental syntax highlighting for mathematical expressions written
310;; in LaTeX (only expressions denoted by `$..$`, `$$..$$`, or `\[..\]`)
311;; can be enabled by setting `markdown-enable-math' to a non-nil value,
312;; either via customize or by placing `(setq markdown-enable-itex t)`
313;; in `.emacs`, and restarting Emacs.
314;;
315;; A [GitHub Flavored Markdown](http://github.github.com/github-flavored-markdown/)
316;; mode, `gfm-mode', is also available. The GitHub implementation of
317;; differs slightly from standard Markdown. Most importantly, newlines are
318;; significant and trigger hard line breaks. As such, `gfm-mode' turns off
319;; `auto-fill-mode' and turns on `longlines-mode'.
320
321;;; Acknowledgments:
322
323;; markdown-mode has benefited greatly from the efforts of the
324;; following people:
325;;
326;; * Cyril Brulebois <cyril.brulebois@enst-bretagne.fr> for Debian packaging.
327;; * Conal Elliott <conal@conal.net> for a font-lock regexp patch.
328;; * Edward O'Connor <hober0@gmail.com> for a font-lock regexp fix and
329;; GitHub Flavored Markdown mode (`gfm-mode').
330;; * Greg Bognar <greg_bognar@hms.harvard.edu> for menus and running
331;; `markdown' with an active region.
332;; * Daniel Burrows <dburrows@debian.org> for filing Debian bug #456592.
333;; * Peter S. Galbraith <psg@debian.org> for maintaining emacs-goodies-el.
334;; * Dmitry Dzhus <mail@sphinx.net.ru> for reference checking functions.
335;; * Bryan Kyle <bryan.kyle@gmail.com> for indentation code.
336;; * Ben Voui <intrigeri@boum.org> for font-lock face customizations.
337;; * Ankit Solanki <ankit.solanki@gmail.com> for longlines.el
338;; compatibility and custom CSS.
339;; * Hilko Bengen <bengen@debian.org> for proper XHTML output.
340;; * Jose A. Ortega Ruiz <jao@gnu.org> for Emacs 23 fixes.
341;; * Alec Resnick <alec@sproutward.org> for bug reports.
342;; * Joost Kremers <j.kremers@em.uni-frankfurt.de> for bug reports
343;; regarding indentation.
344;; * Peter Williams <pezra@barelyenough.org> for fill-paragraph
345;; enhancements.
346;; * George Ogata <george.ogata@gmail.com> for fixing several
347;; byte-compilation warnings.
348;; * Eric Merritt <ericbmerritt@gmail.com> for wiki link features.
349;; * Philippe Ivaldi <pivaldi@sfr.fr> for XHTML preview
350;; customizations and XHTML export.
351;; * Jeremiah Dodds <jeremiah.dodds@gmail.com> for supporting
352;; Markdown processors which do not accept input from stdin.
353;; * Werner Dittmann <werner.dittmann@t-online.de> for bug reports
354;; regarding the cl dependency and auto-fill-mode and indentation.
355
356;;; Bugs:
357
358;; Although markdown-mode is developed and tested primarily using
359;; GNU Emacs 24, compatibility with earlier Emacsen is also a
360;; priority.
361;;
362;; If you find any bugs in markdown-mode, please construct a test case
363;; or a patch and email me at <jrblevin@sdf.org>.
364
365;;; History:
366
367;; markdown-mode was written and is maintained by Jason Blevins. The
368;; first version was released on May 24, 2007.
369;;
370;; * 2007-05-24: Version 1.1
371;; * 2007-05-25: Version 1.2
372;; * 2007-06-05: [Version 1.3][]
373;; * 2007-06-29: Version 1.4
374;; * 2008-05-24: [Version 1.5][]
375;; * 2008-06-04: [Version 1.6][]
376;; * 2009-10-01: [Version 1.7][]
377;; * 2011-08-12: [Version 1.8][]
378;; * 2011-08-15: [Version 1.8.1][]
379;;
380;; [Version 1.3]: http://jblevins.org/projects/markdown-mode/rev-1-3
381;; [Version 1.5]: http://jblevins.org/projects/markdown-mode/rev-1-5
382;; [Version 1.6]: http://jblevins.org/projects/markdown-mode/rev-1-6
383;; [Version 1.7]: http://jblevins.org/projects/markdown-mode/rev-1-7
384;; [Version 1.8]: http://jblevins.org/projects/markdown-mode/rev-1-8
385;; [Version 1.8.1]: http://jblevins.org/projects/markdown-mode/rev-1-8-1
386
387
388;;; Code:
389
390(require 'easymenu)
391(require 'outline)
392(require 'cl)
393
394;;; Constants =================================================================
395
396(defconst markdown-mode-version "1.8.1"
397 "Markdown mode version number.")
398
399(defconst markdown-output-buffer-name "*markdown-output*"
400 "Name of temporary buffer for markdown command output.")
401
402;;; Customizable variables ====================================================
403
404(defvar markdown-mode-hook nil
405 "Hook runs when Markdown mode is loaded.")
406
407(defgroup markdown nil
408 "Major mode for editing text files in Markdown format."
409 :prefix "markdown-"
410 :group 'wp
411 :link '(url-link "http://jblevins.org/projects/markdown-mode/"))
412
413(defcustom markdown-command "markdown"
414 "Command to run markdown."
415 :group 'markdown
416 :type 'string)
417
418(defcustom markdown-command-needs-filename nil
419 "Set to non-nil if `markdown-command' does not accept input from stdin.
420Instead, it will be passed a filename as the final command-line
421option. As a result, you will only be able to run Markdown from
422buffers which are visiting a file."
423 :group 'markdown
424 :type 'boolean)
425
426(defcustom markdown-hr-string "* * * * *"
427 "String to use for horizonal rules."
428 :group 'markdown
429 :type 'string)
430
431(defcustom markdown-bold-underscore nil
432 "Use two underscores for bold instead of two asterisks."
433 :group 'markdown
434 :type 'boolean)
435
436(defcustom markdown-italic-underscore nil
437 "Use underscores for italic instead of asterisks."
438 :group 'markdown
439 :type 'boolean)
440
441(defcustom markdown-indent-function 'markdown-indent-line
442 "Function to use to indent."
443 :group 'markdown
444 :type 'function)
445
446(defcustom markdown-indent-on-enter t
447 "Automatically indent new lines when enter key is pressed."
448 :group 'markdown
449 :type 'boolean)
450
451(defcustom markdown-follow-wiki-link-on-enter t
452 "Follow wiki link at point (if any) when the enter key is pressed."
453 :group 'markdown
454 :type 'boolean)
455
456(defcustom markdown-uri-types
457 '("acap" "cid" "data" "dav" "fax" "file" "ftp" "gopher" "http" "https"
458 "imap" "ldap" "mailto" "mid" "modem" "news" "nfs" "nntp" "pop" "prospero"
459 "rtsp" "service" "sip" "tel" "telnet" "tip" "urn" "vemmi" "wais")
460 "Link types for syntax highlighting of URIs."
461 :group 'markdown
462 :type 'list)
463
464(defcustom markdown-enable-math nil
465 "Syntax highlighting for inline LaTeX expressions.
466This will not take effect until Emacs is restarted."
467 :group 'markdown
468 :type 'boolean)
469
470(defcustom markdown-css-path ""
471 "URL of CSS file to link to in the output XHTML."
472 :group 'markdown
473 :type 'string)
474
475(defcustom markdown-xhtml-header-content ""
476 "Additional content to include in the XHTML <head> block."
477 :group 'markdown
478 :type 'string)
479
480(defcustom markdown-xhtml-standalone-regexp
481 "^\\(\<\?xml\\|\<!DOCTYPE\\|\<html\\)"
482 "Regexp indicating whether `markdown-command' output is standalone XHTML."
483 :group 'markdown
484 :type 'regexp)
485
486;;; Font lock =================================================================
487
488(require 'font-lock)
489
490(defvar markdown-italic-face 'markdown-italic-face
491 "Face name to use for italic text.")
492
493(defvar markdown-bold-face 'markdown-bold-face
494 "Face name to use for bold text.")
495
496(defvar markdown-header-face 'markdown-header-face
497 "Face name to use as a base for headers.")
498
499(defvar markdown-header-face-1 'markdown-header-face-1
500 "Face name to use for level-1 headers.")
501
502(defvar markdown-header-face-2 'markdown-header-face-2
503 "Face name to use for level-2 headers.")
504
505(defvar markdown-header-face-3 'markdown-header-face-3
506 "Face name to use for level-3 headers.")
507
508(defvar markdown-header-face-4 'markdown-header-face-4
509 "Face name to use for level-4 headers.")
510
511(defvar markdown-header-face-5 'markdown-header-face-5
512 "Face name to use for level-5 headers.")
513
514(defvar markdown-header-face-6 'markdown-header-face-6
515 "Face name to use for level-6 headers.")
516
517(defvar markdown-inline-code-face 'markdown-inline-code-face
518 "Face name to use for inline code.")
519
520(defvar markdown-list-face 'markdown-list-face
521 "Face name to use for list markers.")
522
523(defvar markdown-blockquote-face 'markdown-blockquote-face
524 "Face name to use for blockquote.")
525
526(defvar markdown-pre-face 'markdown-pre-face
527 "Face name to use for preformatted text.")
528
529(defvar markdown-link-face 'markdown-link-face
530 "Face name to use for links.")
531
532(defvar markdown-missing-link-face 'markdown-missing-link-face
533 "Face name to use for links where the linked file does not exist.")
534
535(defvar markdown-reference-face 'markdown-reference-face
536 "Face name to use for reference.")
537
538(defvar markdown-url-face 'markdown-url-face
539 "Face name to use for URLs.")
540
541(defvar markdown-link-title-face 'markdown-link-title-face
542 "Face name to use for reference link titles.")
543
544(defvar markdown-comment-face 'markdown-comment-face
545 "Face name to use for HTML comments.")
546
547(defvar markdown-math-face 'markdown-math-face
548 "Face name to use for LaTeX expressions.")
549
550(defgroup markdown-faces nil
551 "Faces used in Markdown Mode"
552 :group 'markdown
553 :group 'faces)
554
555(defface markdown-italic-face
556 '((t :inherit font-lock-variable-name-face :italic t))
557 "Face for italic text."
558 :group 'markdown-faces)
559
560(defface markdown-bold-face
561 '((t :inherit font-lock-variable-name-face :bold t))
562 "Face for bold text."
563 :group 'markdown-faces)
564
565(defface markdown-header-face
566 '((t :inherit font-lock-function-name-face :weight bold))
567 "Base face for headers."
568 :group 'markdown-faces)
569
570(defface markdown-header-face-1
571 '((t :inherit markdown-header-face))
572 "Face for level-1 headers."
573 :group 'markdown-faces)
574
575(defface markdown-header-face-2
576 '((t :inherit markdown-header-face))
577 "Face for level-2 headers."
578 :group 'markdown-faces)
579
580(defface markdown-header-face-3
581 '((t :inherit markdown-header-face))
582 "Face for level-3 headers."
583 :group 'markdown-faces)
584
585(defface markdown-header-face-4
586 '((t :inherit markdown-header-face))
587 "Face for level-4 headers."
588 :group 'markdown-faces)
589
590(defface markdown-header-face-5
591 '((t :inherit markdown-header-face))
592 "Face for level-5 headers."
593 :group 'markdown-faces)
594
595(defface markdown-header-face-6
596 '((t :inherit markdown-header-face))
597 "Face for level-6 headers."
598 :group 'markdown-faces)
599
600(defface markdown-inline-code-face
601 '((t :inherit font-lock-constant-face))
602 "Face for inline code."
603 :group 'markdown-faces)
604
605(defface markdown-list-face
606 '((t :inherit font-lock-builtin-face))
607 "Face for list item markers."
608 :group 'markdown-faces)
609
610(defface markdown-blockquote-face
611 '((t :inherit font-lock-doc-face))
612 "Face for blockquote sections."
613 :group 'markdown-faces)
614
615(defface markdown-pre-face
616 '((t :inherit font-lock-constant-face))
617 "Face for preformatted text."
618 :group 'markdown-faces)
619
620(defface markdown-link-face
621 '((t :inherit font-lock-keyword-face))
622 "Face for links."
623 :group 'markdown-faces)
624
625(defface markdown-missing-link-face
626 '((t :inherit font-lock-warning-face))
627 "Face for missing links."
628 :group 'markdown-faces)
629
630(defface markdown-reference-face
631 '((t :inherit font-lock-type-face))
632 "Face for link references."
633 :group 'markdown-faces)
634
635(defface markdown-url-face
636 '((t :inherit font-lock-string-face))
637 "Face for URLs."
638 :group 'markdown-faces)
639
640(defface markdown-link-title-face
641 '((t :inherit font-lock-comment-face))
642 "Face for reference link titles."
643 :group 'markdown-faces)
644
645(defface markdown-comment-face
646 '((t :inherit font-lock-comment-face))
647 "Face for HTML comments."
648 :group 'markdown-faces)
649
650(defface markdown-math-face
651 '((t :inherit font-lock-string-face))
652 "Face for LaTeX expressions."
653 :group 'markdown-faces)
654
655(defconst markdown-regex-link-inline
656 "\\(!?\\[[^]]*?\\]\\)\\(([^\\)]*)\\)"
657 "Regular expression for a [text](file) or an image link .")
658
659(defconst markdown-regex-link-reference
660 "\\(!?\\[[^]]+?\\]\\)[ ]?\\(\\[[^]]*?\\]\\)"
661 "Regular expression for a reference link [text][id].")
662
663(defconst markdown-regex-reference-definition
664 "^ \\{0,3\\}\\(\\[.+?\\]\\):\\s *\\(.*?\\)\\s *\\( \"[^\"]*\"$\\|$\\)"
665 "Regular expression for a link definition [id]: ...")
666
667(defconst markdown-regex-header-1-atx
668 "^\\(# \\)\\(.*?\\)\\($\\| #+$\\)"
669 "Regular expression for level 1 atx-style (hash mark) headers.")
670
671(defconst markdown-regex-header-2-atx
672 "^\\(## \\)\\(.*?\\)\\($\\| #+$\\)"
673 "Regular expression for level 2 atx-style (hash mark) headers.")
674
675(defconst markdown-regex-header-3-atx
676 "^\\(### \\)\\(.*?\\)\\($\\| #+$\\)"
677 "Regular expression for level 3 atx-style (hash mark) headers.")
678
679(defconst markdown-regex-header-4-atx
680 "^\\(#### \\)\\(.*?\\)\\($\\| #+$\\)"
681 "Regular expression for level 4 atx-style (hash mark) headers.")
682
683(defconst markdown-regex-header-5-atx
684 "^\\(##### \\)\\(.*?\\)\\($\\| #+$\\)"
685 "Regular expression for level 5 atx-style (hash mark) headers.")
686
687(defconst markdown-regex-header-6-atx
688 "^\\(###### \\)\\(.*?\\)\\($\\| #+$\\)"
689 "Regular expression for level 6 atx-style (hash mark) headers.")
690
691(defconst markdown-regex-header-1-setext
692 "^\\(.*\\)\n\\(===+\\)$"
693 "Regular expression for level 1 setext-style (underline) headers.")
694
695(defconst markdown-regex-header-2-setext
696 "^\\(.*\\)\n\\(---+\\)$"
697 "Regular expression for level 2 setext-style (underline) headers.")
698
699(defconst markdown-regex-hr
700 "^\\(\\*[ ]?\\*[ ]?\\*[ ]?[\\* ]*\\|-[ ]?-[ ]?-[--- ]*\\)$"
701 "Regular expression for matching Markdown horizontal rules.")
702
703(defconst markdown-regex-code
704 "\\(^\\|[^\\]\\)\\(\\(`\\{1,2\\}\\)\\([^ \\]\\|[^ ]\\(.\\|\n[^\n]\\)*?[^ \\]\\)\\3\\)"
705 "Regular expression for matching inline code fragments.")
706
707(defconst markdown-regex-pre
708 "^\\( \\|\t\\).*$"
709 "Regular expression for matching preformatted text sections.")
710
711(defconst markdown-regex-list
712 "^[ \t]*\\([0-9]+\\.\\|[\\*\\+-]\\) "
713 "Regular expression for matching list markers.")
714
715(defconst markdown-regex-bold
716 "\\(^\\|[^\\]\\)\\(\\([*_]\\{2\\}\\)\\(.\\|\n[^\n]\\)*?[^\\ ]\\3\\)"
717 "Regular expression for matching bold text.")
718
719(defconst markdown-regex-italic
720 "\\(^\\|[^\\]\\)\\(\\([*_]\\)\\([^ \\]\\3\\|[^ ]\\(.\\|\n[^\n]\\)*?[^\\ ]\\3\\)\\)"
721 "Regular expression for matching italic text.")
722
723(defconst markdown-regex-blockquote
724 "^>.*$"
725 "Regular expression for matching blockquote lines.")
726
727(defconst markdown-regex-line-break
728 " $"
729 "Regular expression for matching line breaks.")
730
731(defconst markdown-regex-wiki-link
732 "\\[\\[\\([^]|]+\\)\\(|\\([^]]+\\)\\)?\\]\\]"
733 "Regular expression for matching wiki links.
734This matches typical bracketed [[WikiLinks]] as well as 'aliased'
735wiki links of the form [[PageName|link text]]. In this regular
736expression, #1 matches the page name and #3 matches the link
737text.")
738
739(defconst markdown-regex-uri
740 (concat
741 "\\(" (mapconcat 'identity markdown-uri-types "\\|")
742 "\\):[^]\t\n\r<>,;() ]+")
743 "Regular expression for matching inline URIs.")
744
745(defconst markdown-regex-angle-uri
746 (concat
747 "\\(<\\)\\("
748 (mapconcat 'identity markdown-uri-types "\\|")
749 "\\):[^]\t\n\r<>,;()]+\\(>\\)")
750 "Regular expression for matching inline URIs in angle brackets.")
751
752(defconst markdown-regex-email
753 "<\\(\\sw\\|\\s_\\|\\s.\\)+@\\(\\sw\\|\\s_\\|\\s.\\)+>"
754 "Regular expression for matching inline email addresses.")
755
756(defconst markdown-regex-latex-expression
757 "\\(^\\|[^\\]\\)\\(\\$\\($\\([^\\$]\\|\\\\.\\)*\\$\\|\\([^\\$]\\|\\\\.\\)*\\)\\$\\)"
758 "Regular expression for itex $..$ or $$..$$ math mode expressions.")
759
760(defconst markdown-regex-latex-display
761 "^\\\\\\[\\(.\\|\n\\)*?\\\\\\]$"
762 "Regular expression for itex \[..\] display mode expressions.")
763
764(defconst markdown-regex-list-indent
765 "^\\(\\s *\\)\\([0-9]+\\.\\|[\\*\\+-]\\)\\(\\s +\\)"
766 "Regular expression for matching indentation of list items.")
767
768(defvar markdown-mode-font-lock-keywords-basic
769 (list
770 '(markdown-match-pre-blocks 0 markdown-pre-face t t)
771 (cons markdown-regex-blockquote 'markdown-blockquote-face)
772 (cons markdown-regex-header-1-setext 'markdown-header-face-1)
773 (cons markdown-regex-header-2-setext 'markdown-header-face-2)
774 (cons markdown-regex-header-1-atx 'markdown-header-face-1)
775 (cons markdown-regex-header-2-atx 'markdown-header-face-2)
776 (cons markdown-regex-header-3-atx 'markdown-header-face-3)
777 (cons markdown-regex-header-4-atx 'markdown-header-face-4)
778 (cons markdown-regex-header-5-atx 'markdown-header-face-5)
779 (cons markdown-regex-header-6-atx 'markdown-header-face-6)
780 (cons markdown-regex-hr 'markdown-header-face)
781 '(markdown-match-comments 0 markdown-comment-face t t)
782 (cons markdown-regex-code '(2 markdown-inline-code-face))
783 (cons markdown-regex-list 'markdown-list-face)
784 (cons markdown-regex-link-inline
785 '((0 (let
786 ((link-beg (match-beginning 1))
787 (link-end (match-end 1))
788 (url-beg (match-beginning 2))
789 (url-end (match-end 2)))
790 (markdown-linkd-render-link link-beg link-end url-beg url-end markdown-link-face)
791 'markdown-link-face)
792 prepend)))
793 (cons markdown-regex-link-reference
794 '((1 markdown-link-face t)
795 (2 markdown-reference-face t)))
796 (cons markdown-regex-reference-definition
797 '((1 markdown-reference-face t)
798 (2 markdown-url-face t)
799 (3 markdown-link-title-face t)))
800 (cons markdown-regex-bold '(2 markdown-bold-face))
801 (cons markdown-regex-italic '(2 markdown-italic-face))
802 (cons markdown-regex-angle-uri 'markdown-link-face)
803 (cons markdown-regex-uri 'markdown-link-face)
804 (cons markdown-regex-email 'markdown-link-face)
805 )
806 "Syntax highlighting for Markdown files.")
807
808(defconst markdown-mode-font-lock-keywords-latex
809 (list
810 ;; Math mode $..$ or $$..$$
811 (cons markdown-regex-latex-expression '(2 markdown-math-face))
812 ;; Display mode equations with brackets: \[ \]
813 (cons markdown-regex-latex-display 'markdown-math-face)
814 ;; Equation reference (eq:foo)
815 (cons "(eq:\\w+)" 'markdown-reference-face)
816 ;; Equation reference \eqref{foo}
817 (cons "\\\\eqref{\\w+}" 'markdown-reference-face))
818 "Syntax highlighting for LaTeX fragments.")
819
820(defvar markdown-mode-font-lock-keywords
821 (append
822 (if markdown-enable-math
823 markdown-mode-font-lock-keywords-latex)
824 markdown-mode-font-lock-keywords-basic)
825 "Default highlighting expressions for Markdown mode.")
826
827
828
829;;; Markdown parsing functions ================================================
830
831(defun markdown-cur-line-blank-p ()
832 "Return t if the current line is blank and nil otherwise."
833 (save-excursion
834 (beginning-of-line)
835 (re-search-forward "^\\s *$" (point-at-eol) t)))
836
837(defun markdown-prev-line-blank-p ()
838 "Return t if the previous line is blank and nil otherwise.
839If we are at the first line, then consider the previous line to be blank."
840 (save-excursion
841 (if (= (point-at-bol) (point-min))
842 t
843 (forward-line -1)
844 (markdown-cur-line-blank-p))))
845
846(defun markdown-prev-line-indent-p ()
847 "Return t if the previous line is indented and nil otherwise."
848 (save-excursion
849 (forward-line -1)
850 (goto-char (point-at-bol))
851 (if (re-search-forward "^\\s " (point-at-eol) t) t)))
852
853(defun markdown-cur-line-indent ()
854 "Return the number of leading whitespace characters in the current line."
855 (save-excursion
856 (goto-char (point-at-bol))
857 (re-search-forward "^\\s +" (point-at-eol) t)
858 (current-column)))
859
860(defun markdown-prev-line-indent ()
861 "Return the number of leading whitespace characters in the previous line."
862 (save-excursion
863 (forward-line -1)
864 (markdown-cur-line-indent)))
865
866(defun markdown-cur-non-list-indent ()
867 "Return the number of leading whitespace characters in the current line."
868 (save-excursion
869 (beginning-of-line)
870 (when (re-search-forward markdown-regex-list-indent (point-at-eol) t)
871 (current-column))))
872
873(defun markdown-prev-non-list-indent ()
874 "Return position of the first non-list-marker on the previous line."
875 (save-excursion
876 (forward-line -1)
877 (markdown-cur-non-list-indent)))
878
879(defun markdown--next-block ()
880 "Move the point to the start of the next text block."
881 (forward-line)
882 (while (and (or (not (markdown-prev-line-blank-p))
883 (markdown-cur-line-blank-p))
884 (not (eobp)))
885 (forward-line)))
886
887(defun markdown--end-of-level (level)
888 "Move the point to the end of region with indentation at least LEVEL."
889 (let (indent)
890 (while (and (not (< (setq indent (markdown-cur-line-indent)) level))
891 (not (>= indent (+ level 4)))
892 (not (eobp)))
893 (markdown--next-block))
894 (unless (eobp)
895 ;; Move back before any trailing blank lines
896 (while (and (markdown-prev-line-blank-p)
897 (not (bobp)))
898 (forward-line -1))
899 (forward-line -1)
900 (end-of-line))))
901
902; From html-helper-mode
903(defun markdown-match-comments (last)
904 "Match HTML comments from the point to LAST."
905 (cond ((search-forward "<!--" last t)
906 (backward-char 4)
907 (let ((beg (point)))
908 (cond ((search-forward-regexp "--[ \t]*>" last t)
909 (set-match-data (list beg (point)))
910 t)
911 (t nil))))
912 (t nil)))
913
914(defun markdown-match-pre-blocks (last)
915 "Match Markdown pre blocks from point to LAST.
916A region matches as if it is indented at least four spaces
917relative to the nearest previous block of lesser non-list-marker
918indentation."
919
920 (let (cur-begin cur-end cur-indent prev-indent prev-list stop match found)
921 ;; Don't start in the middle of a block
922 (unless (and (bolp)
923 (markdown-prev-line-blank-p)
924 (not (markdown-cur-line-blank-p)))
925 (markdown--next-block))
926
927 ;; Move to the first full block in the region with indent 4 or more
928 (while (and (not (>= (setq cur-indent (markdown-cur-line-indent)) 4))
929 (not (>= (point) last)))
930 (markdown--next-block))
931 (setq cur-begin (point))
932 (markdown--end-of-level cur-indent)
933 (setq cur-end (point))
934 (setq match nil)
935 (setq stop (> cur-begin cur-end))
936
937 (while (and (<= cur-end last) (not stop) (not match))
938 ;; Move to the nearest preceding block of lesser (non-marker) indentation
939 (setq prev-indent (+ cur-indent 1))
940 (goto-char cur-begin)
941 (setq found nil)
942 (while (and (>= prev-indent cur-indent)
943 (not (and prev-list
944 (eq prev-indent cur-indent)))
945 (not (bobp)))
946
947 ;; Move point to the last line of the previous block.
948 (forward-line -1)
949 (while (and (markdown-cur-line-blank-p)
950 (not (bobp)))
951 (forward-line -1))
952
953 ;; Update the indentation level using either the
954 ;; non-list-marker indentation, if the previous line is the
955 ;; start of a list, or the actual indentation.
956 (setq prev-list (markdown-cur-non-list-indent))
957 (setq prev-indent (or prev-list
958 (markdown-cur-line-indent)))
959 (setq found t))
960
961 ;; If the loop didn't execute
962 (unless found
963 (setq prev-indent 0))
964
965 ;; Compare with prev-indent minus its remainder mod 4
966 (setq prev-indent (- prev-indent (mod prev-indent 4)))
967
968 ;; Set match data and return t if we have a match
969 (if (>= cur-indent (+ prev-indent 4))
970 ;; Match
971 (progn
972 (setq match t)
973 (set-match-data (list cur-begin cur-end))
974 ;; Leave point at end of block
975 (goto-char cur-end)
976 (forward-line))
977
978 ;; Move to the next block (if possible)
979 (goto-char cur-end)
980 (markdown--next-block)
981 (setq cur-begin (point))
982 (setq cur-indent (markdown-cur-line-indent))
983 (markdown--end-of-level cur-indent)
984 (setq cur-end (point))
985 (setq stop (equal cur-begin cur-end))))
986 match))
987
988(defun markdown-font-lock-extend-region ()
989 "Extend the search region to include an entire block of text.
990This helps improve font locking for block constructs such as pre blocks."
991 ;; Avoid compiler warnings about these global variables from font-lock.el.
992 ;; See the documentation for variable `font-lock-extend-region-functions'.
993 (eval-when-compile (defvar font-lock-beg) (defvar font-lock-end))
994 (save-excursion
995 (goto-char font-lock-beg)
996 (let ((found (re-search-backward "\n\n" nil t)))
997 (when found
998 (goto-char font-lock-end)
999 (when (re-search-forward "\n\n" nil t)
1000 (beginning-of-line)
1001 (setq font-lock-end (point)))
1002 (setq font-lock-beg found)))))
1003
1004
1005
1006;;; Syntax Table ==============================================================
1007
1008(defvar markdown-mode-syntax-table
1009 (let ((markdown-mode-syntax-table (make-syntax-table)))
1010 (modify-syntax-entry ?\" "w" markdown-mode-syntax-table)
1011 markdown-mode-syntax-table)
1012 "Syntax table for `markdown-mode'.")
1013
1014
1015
1016;;; Element Insertion =========================================================
1017
1018(defun markdown-wrap-or-insert (s1 s2)
1019 "Insert the strings S1 and S2.
1020If Transient Mark mode is on and a region is active, wrap the strings S1
1021and S2 around the region."
1022 (if (and transient-mark-mode mark-active)
1023 (let ((a (region-beginning)) (b (region-end)))
1024 (goto-char a)
1025 (insert s1)
1026 (goto-char (+ b (length s1)))
1027 (insert s2))
1028 (insert s1 s2)))
1029
1030(defun markdown-insert-hr ()
1031 "Insert a horizonal rule using `markdown-hr-string'."
1032 (interactive)
1033 ;; Leading blank line
1034 (when (and (>= (point) (+ (point-min) 2))
1035 (not (looking-back "\n\n" 2)))
1036 (insert "\n"))
1037 ;; Insert custom HR string
1038 (insert (concat markdown-hr-string "\n"))
1039 ;; Following blank line
1040 (backward-char)
1041 (unless (looking-at "\n\n")
1042 (insert "\n")))
1043
1044(defun markdown-insert-bold ()
1045 "Insert markup for a bold word or phrase.
1046If Transient Mark mode is on and a region is active, it is made bold."
1047 (interactive)
1048 (if markdown-bold-underscore
1049 (markdown-wrap-or-insert "__" "__")
1050 (markdown-wrap-or-insert "**" "**"))
1051 (backward-char 2))
1052
1053(defun markdown-insert-italic ()
1054 "Insert markup for an italic word or phrase.
1055If Transient Mark mode is on and a region is active, it is made italic."
1056 (interactive)
1057 (if markdown-italic-underscore
1058 (markdown-wrap-or-insert "_" "_")
1059 (markdown-wrap-or-insert "*" "*"))
1060 (backward-char 1))
1061
1062(defun markdown-insert-code ()
1063 "Insert markup for an inline code fragment.
1064If Transient Mark mode is on and a region is active, it is marked
1065as inline code."
1066 (interactive)
1067 (markdown-wrap-or-insert "`" "`")
1068 (backward-char 1))
1069
1070(defun markdown-insert-link ()
1071 "Insert an inline link of the form []().
1072If Transient Mark mode is on and a region is active, it is used
1073as the link text."
1074 (interactive)
1075 (markdown-wrap-or-insert "[" "]")
1076 (insert "()")
1077 (backward-char 1))
1078
1079(defun markdown-insert-wiki-link ()
1080 "Insert a wiki link of the form [[WikiLink]].
1081If Transient Mark mode is on and a region is active, it is used
1082as the link text."
1083 (interactive)
1084 (markdown-wrap-or-insert "[[" "]]")
1085 (backward-char 2))
1086
1087(defun markdown-insert-image ()
1088 "Insert an inline image tag of the form ![]().
1089If Transient Mark mode is on and a region is active, it is used
1090as the alt text of the image."
1091 (interactive)
1092 (markdown-wrap-or-insert "![" "]")
1093 (insert "()")
1094 (backward-char 1))
1095
1096(defun markdown-insert-header-1 ()
1097 "Insert a first level atx-style (hash mark) header.
1098If Transient Mark mode is on and a region is active, it is used
1099as the header text."
1100 (interactive)
1101 (markdown-insert-header 1))
1102
1103(defun markdown-insert-header-2 ()
1104 "Insert a second level atx-style (hash mark) header.
1105If Transient Mark mode is on and a region is active, it is used
1106as the header text."
1107 (interactive)
1108 (markdown-insert-header 2))
1109
1110(defun markdown-insert-header-3 ()
1111 "Insert a third level atx-style (hash mark) header.
1112If Transient Mark mode is on and a region is active, it is used
1113as the header text."
1114 (interactive)
1115 (markdown-insert-header 3))
1116
1117(defun markdown-insert-header-4 ()
1118 "Insert a fourth level atx-style (hash mark) header.
1119If Transient Mark mode is on and a region is active, it is used
1120as the header text."
1121 (interactive)
1122 (markdown-insert-header 4))
1123
1124(defun markdown-insert-header-5 ()
1125 "Insert a fifth level atx-style (hash mark) header.
1126If Transient Mark mode is on and a region is active, it is used
1127as the header text."
1128 (interactive)
1129 (markdown-insert-header 5))
1130
1131(defun markdown-insert-header-6 ()
1132 "Insert a sixth level atx-style (hash mark) header.
1133If Transient Mark mode is on and a region is active, it is used
1134as the header text."
1135 (interactive)
1136 (markdown-insert-header 6))
1137
1138(defun markdown-insert-header (n)
1139 "Insert an atx-style (hash mark) header.
1140With no prefix argument, insert a level-1 header. With prefix N,
1141insert a level-N header. If Transient Mark mode is on and the
1142region is active, it is used as the header text."
1143 (interactive "p")
1144 (unless n ; Test to see if n is defined
1145 (setq n 1)) ; Default to level 1 header
1146 (let (hdr hdrl hdrr)
1147 (dotimes (count n hdr)
1148 (setq hdr (concat "#" hdr))) ; Build a hash mark header string
1149 (setq hdrl (concat hdr " "))
1150 (setq hdrr (concat " " hdr))
1151 (markdown-wrap-or-insert hdrl hdrr))
1152 (backward-char (+ 1 n)))
1153
1154(defun markdown-insert-title ()
1155 "Insert a setext-style (underline) first level header.
1156If Transient Mark mode is on and a region is active, it is used
1157as the header text."
1158 (interactive)
1159 (if (and transient-mark-mode mark-active)
1160 (let ((a (region-beginning))
1161 (b (region-end))
1162 (len 0)
1163 (hdr))
1164 (setq len (- b a))
1165 (dotimes (count len hdr)
1166 (setq hdr (concat "=" hdr))) ; Build a === title underline
1167 (end-of-line)
1168 (insert "\n" hdr "\n"))
1169 (insert "\n==========\n")
1170 (backward-char 12)))
1171
1172(defun markdown-insert-section ()
1173 "Insert a setext-style (underline) second level header.
1174If Transient Mark mode is on and a region is active, it is used
1175as the header text."
1176 (interactive)
1177 (if (and transient-mark-mode mark-active)
1178 (let ((a (region-beginning))
1179 (b (region-end))
1180 (len 0)
1181 (hdr))
1182 (setq len (- b a))
1183 (dotimes (count len hdr)
1184 (setq hdr (concat "-" hdr))) ; Build a --- section underline
1185 (end-of-line)
1186 (insert "\n" hdr "\n"))
1187 (insert "\n----------\n")
1188 (backward-char 12)))
1189
1190(defun markdown-insert-blockquote ()
1191 "Start a blockquote section (or blockquote the region).
1192If Transient Mark mode is on and a region is active, it is used as
1193the blockquote text."
1194 (interactive)
1195 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
1196 (markdown-blockquote-region (region-beginning) (region-end))
1197 (insert "> ")))
1198
1199(defun markdown-block-region (beg end prefix)
1200 "Format the region using a block prefix.
1201Arguments BEG and END specify the beginning and end of the
1202region. The characters PREFIX will appear at the beginning
1203of each line."
1204 (if mark-active
1205 (save-excursion
1206 ;; Ensure that there is a leading blank line
1207 (goto-char beg)
1208 (when (and (>= (point) (+ (point-min) 2))
1209 (not (looking-back "\n\n" 2)))
1210 (insert "\n")
1211 (setq beg (1+ beg))
1212 (setq end (1+ end)))
1213 ;; Move back before any blank lines at the end
1214 (goto-char end)
1215 (while (and (looking-back "\n" 1)
1216 (not (equal (point) (point-min))))
1217 (backward-char)
1218 (setq end (1- end)))
1219 ;; Ensure that there is a trailing blank line
1220 (goto-char end)
1221 (if (not (or (looking-at "\n\n")
1222 (and (equal (1+ end) (point-max)) (looking-at "\n"))))
1223 (insert "\n"))
1224 ;; Insert PREFIX
1225 (goto-char beg)
1226 (beginning-of-line)
1227 (while (< (point-at-bol) end)
1228 (insert prefix)
1229 (setq end (+ (length prefix) end))
1230 (forward-line)))))
1231
1232(defun markdown-blockquote-region (beg end)
1233 "Blockquote the region.
1234Arguments BEG and END specify the beginning and end of the region."
1235 (interactive "*r")
1236 (markdown-block-region beg end "> "))
1237
1238(defun markdown-insert-pre ()
1239 "Start a preformatted section (or apply to the region).
1240If Transient Mark mode is on and a region is active, it is marked
1241as preformatted text."
1242 (interactive)
1243 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
1244 (markdown-pre-region (region-beginning) (region-end))
1245 (insert " ")))
1246
1247(defun markdown-pre-region (beg end)
1248 "Format the region as preformatted text.
1249Arguments BEG and END specify the beginning and end of the region."
1250 (interactive "*r")
1251 (markdown-block-region beg end " "))
1252
1253;;; Indentation ====================================================================
1254
1255(defun markdown-indent-find-next-position (cur-pos positions)
1256 "Return the position after the index of CUR-POS in POSITIONS."
1257 (while (and positions
1258 (not (equal cur-pos (car positions))))
1259 (setq positions (cdr positions)))
1260 (or (cadr positions) 0))
1261
1262(defun markdown-indent-line ()
1263 "Indent the current line using some heuristics.
1264If the _previous_ command was either `markdown-enter-key' or
1265`markdown-cycle', then we should cycle to the next
1266reasonable indentation position. Otherwise, we could have been
1267called directly by `markdown-enter-key', by an initial call of
1268`markdown-cycle', or indirectly by `auto-fill-mode'. In
1269these cases, indent to the default position."
1270 (interactive)
1271 (let ((positions (markdown-calc-indents))
1272 (cur-pos (current-column)))
1273 (if (not (equal this-command 'markdown-cycle))
1274 (indent-line-to (car positions))
1275 (setq positions (sort (delete-dups positions) '<))
1276 (indent-line-to
1277 (markdown-indent-find-next-position cur-pos positions)))))
1278
1279(defun markdown-calc-indents ()
1280 "Return a list of indentation columns to cycle through.
1281The first element in the returned list should be considered the
1282default indentation level."
1283 (let (pos prev-line-pos positions)
1284
1285 ;; Previous line indent
1286 (setq prev-line-pos (markdown-prev-line-indent))
1287 (setq positions (cons prev-line-pos positions))
1288
1289 ;; Previous non-list-marker indent
1290 (setq pos (markdown-prev-non-list-indent))
1291 (if pos
1292 (setq positions (cons pos positions)))
1293
1294 ;; Indentation of the previous line + tab-width
1295 (cond
1296 (prev-line-pos
1297 (setq positions (cons (+ prev-line-pos tab-width) positions)))
1298 (t
1299 (setq positions (cons tab-width positions))))
1300
1301 ;; Indentation of the previous line - tab-width
1302 (if (and prev-line-pos
1303 (> prev-line-pos tab-width))
1304 (setq positions (cons (- prev-line-pos tab-width) positions)))
1305
1306 ;; Indentation of preceeding list item
1307 (setq pos
1308 (save-excursion
1309 (forward-line -1)
1310 (catch 'break
1311 (while (not (equal (point) (point-min)))
1312 (forward-line -1)
1313 (goto-char (point-at-bol))
1314 (when (re-search-forward markdown-regex-list-indent (point-at-eol) t)
1315 (throw 'break (length (match-string 1)))))
1316 nil)))
1317 (if (and pos (not (eq pos prev-line-pos)))
1318 (setq positions (cons pos positions)))
1319
1320 ;; First column
1321 (setq positions (cons 0 positions))
1322
1323 (reverse positions)))
1324
1325(defun markdown-do-normal-return ()
1326 "Insert a newline and optionally indent the next line."
1327 (newline)
1328 (if markdown-indent-on-enter
1329 (funcall indent-line-function)))
1330
1331(defun markdown-enter-key ()
1332 "Handle RET according to context.
1333If there is a wiki link at the point, follow it unless
1334`markdown-follow-wiki-link-on-enter' is nil. Otherwise, process
1335it in the usual way."
1336 (interactive)
1337 (if (and markdown-follow-wiki-link-on-enter (markdown-wiki-link-p))
1338 (markdown-follow-wiki-link-at-point)
1339 (markdown-do-normal-return)))
1340
1341
1342
1343;;; Keymap ====================================================================
1344
1345(defvar markdown-mode-map
1346 (let ((map (make-keymap)))
1347 ;; Element insertion
1348 (define-key map "\C-c\C-al" 'markdown-insert-link)
1349 (define-key map "\C-c\C-aw" 'markdown-insert-wiki-link)
1350 (define-key map "\C-c\C-ii" 'markdown-insert-image)
1351 (define-key map "\C-c\C-t1" 'markdown-insert-header-1)
1352 (define-key map "\C-c\C-t2" 'markdown-insert-header-2)
1353 (define-key map "\C-c\C-t3" 'markdown-insert-header-3)
1354 (define-key map "\C-c\C-t4" 'markdown-insert-header-4)
1355 (define-key map "\C-c\C-t5" 'markdown-insert-header-5)
1356 (define-key map "\C-c\C-t6" 'markdown-insert-header-6)
1357 (define-key map "\C-c\C-pb" 'markdown-insert-bold)
1358 (define-key map "\C-c\C-ss" 'markdown-insert-bold)
1359 (define-key map "\C-c\C-pi" 'markdown-insert-italic)
1360 (define-key map "\C-c\C-se" 'markdown-insert-italic)
1361 (define-key map "\C-c\C-pf" 'markdown-insert-code)
1362 (define-key map "\C-c\C-sc" 'markdown-insert-code)
1363 (define-key map "\C-c\C-sb" 'markdown-insert-blockquote)
1364 (define-key map "\C-c\C-s\C-b" 'markdown-blockquote-region)
1365 (define-key map "\C-c\C-sp" 'markdown-insert-pre)
1366 (define-key map "\C-c\C-s\C-p" 'markdown-pre-region)
1367 (define-key map "\C-c-" 'markdown-insert-hr)
1368 (define-key map "\C-c\C-tt" 'markdown-insert-title)
1369 (define-key map "\C-c\C-ts" 'markdown-insert-section)
1370 ;; WikiLink Following
1371 (define-key map "\C-c\C-f" 'markdown-follow-wiki-link-at-point)
1372 (define-key map "\M-n" 'markdown-next-wiki-link)
1373 (define-key map "\M-p" 'markdown-previous-wiki-link)
1374 ;; Indentation
1375 (define-key map "\C-m" 'markdown-enter-key)
1376 ;; Visibility cycling
1377 (define-key map (kbd "<tab>") 'markdown-cycle)
1378 (define-key map (kbd "<S-iso-lefttab>") 'markdown-shifttab)
1379 ;; Header navigation
1380 (define-key map (kbd "C-M-n") 'outline-next-visible-heading)
1381 (define-key map (kbd "C-M-p") 'outline-previous-visible-heading)
1382 (define-key map (kbd "C-M-f") 'outline-forward-same-level)
1383 (define-key map (kbd "C-M-b") 'outline-backward-same-level)
1384 (define-key map (kbd "C-M-u") 'outline-up-heading)
1385 ;; Markdown functions
1386 (define-key map "\C-c\C-cm" 'markdown)
1387 (define-key map "\C-c\C-cp" 'markdown-preview)
1388 (define-key map "\C-c\C-ce" 'markdown-export)
1389 (define-key map "\C-c\C-cv" 'markdown-export-and-view)
1390 ;; References
1391 (define-key map "\C-c\C-cc" 'markdown-check-refs)
1392 map)
1393 "Keymap for Markdown major mode.")
1394
1395;;; Menu ==================================================================
1396
1397(easy-menu-define markdown-mode-menu markdown-mode-map
1398 "Menu for Markdown mode"
1399 '("Markdown"
1400 ("Show/Hide"
1401 ["Cycle visibility" markdown-cycle (outline-on-heading-p)]
1402 ["Cycle global visibility" markdown-shifttab])
1403 "---"
1404 ["Compile" markdown]
1405 ["Preview" markdown-preview]
1406 ["Export" markdown-export]
1407 ["Export & View" markdown-export-and-view]
1408 "---"
1409 ("Headers (setext)"
1410 ["Insert Title" markdown-insert-title]
1411 ["Insert Section" markdown-insert-section])
1412 ("Headers (atx)"
1413 ["First level" markdown-insert-header-1]
1414 ["Second level" markdown-insert-header-2]
1415 ["Third level" markdown-insert-header-3]
1416 ["Fourth level" markdown-insert-header-4]
1417 ["Fifth level" markdown-insert-header-5]
1418 ["Sixth level" markdown-insert-header-6])
1419 "---"
1420 ["Bold" markdown-insert-bold]
1421 ["Italic" markdown-insert-italic]
1422 ["Blockquote" markdown-insert-blockquote]
1423 ["Preformatted" markdown-insert-pre]
1424 ["Code" markdown-insert-code]
1425 "---"
1426 ["Insert inline link" markdown-insert-link]
1427 ["Insert image" markdown-insert-image]
1428 ["Insert horizontal rule" markdown-insert-hr]
1429 "---"
1430 ["Check references" markdown-check-refs]
1431 "---"
1432 ["Version" markdown-show-version]
1433 ))
1434
1435
1436
1437;;; References ================================================================
1438
1439;;; Undefined reference checking code by Dmitry Dzhus <mail@sphinx.net.ru>.
1440
1441(defconst markdown-refcheck-buffer
1442 "*Undefined references for %BUFFER%*"
1443 "Pattern for name of buffer for listing undefined references.
1444The string %BUFFER% will be replaced by the corresponding
1445`markdown-mode' buffer name.")
1446
1447(defun markdown-has-reference-definition (reference)
1448 "Find out whether Markdown REFERENCE is defined.
1449
1450REFERENCE should include the square brackets, like [this]."
1451 (let ((reference (downcase reference)))
1452 (save-excursion
1453 (goto-char (point-min))
1454 (catch 'found
1455 (while (re-search-forward markdown-regex-reference-definition nil t)
1456 (when (string= reference (downcase (match-string-no-properties 1)))
1457 (throw 'found t)))))))
1458
1459(defun markdown-get-undefined-refs ()
1460 "Return a list of undefined Markdown references.
1461
1462Result is an alist of pairs (reference . occurencies), where
1463occurencies is itself another alist of pairs (label .
1464line-number).
1465
1466For example, an alist corresponding to [Nice editor][Emacs] at line 12,
1467\[GNU Emacs][Emacs] at line 45 and [manual][elisp] at line 127 is
1468\((\"[emacs]\" (\"[Nice editor]\" . 12) (\"[GNU Emacs]\" . 45)) (\"[elisp]\" (\"[manual]\" . 127)))."
1469 (let ((missing))
1470 (save-excursion
1471 (goto-char (point-min))
1472 (while
1473 (re-search-forward markdown-regex-link-reference nil t)
1474 (let* ((label (match-string-no-properties 1))
1475 (reference (match-string-no-properties 2))
1476 (target (downcase (if (string= reference "[]") label reference))))
1477 (unless (markdown-has-reference-definition target)
1478 (let ((entry (assoc target missing)))
1479 (if (not entry)
1480 (add-to-list 'missing (cons target
1481 (list (cons label (markdown-line-number-at-pos)))) t)
1482 (setcdr entry
1483 (append (cdr entry) (list (cons label (markdown-line-number-at-pos))))))))))
1484 missing)))
1485
1486(defun markdown-add-missing-ref-definition (ref buffer &optional recheck)
1487 "Add blank REF definition to the end of BUFFER.
1488
1489REF is a Markdown reference in square brackets, like \"[lisp-history]\".
1490
1491When RECHECK is non-nil, BUFFER gets rechecked for undefined
1492references so that REF disappears from the list of those links."
1493 (with-current-buffer buffer
1494 (when (not (eq major-mode 'markdown-mode))
1495 (error "Not available in current mode"))
1496 (goto-char (point-max))
1497 (indent-new-comment-line)
1498 (insert (concat ref ": ")))
1499 (switch-to-buffer-other-window buffer)
1500 (goto-char (point-max))
1501 (when recheck
1502 (markdown-check-refs t)))
1503
1504;; Button which adds an empty Markdown reference definition to the end
1505;; of buffer specified as its 'target-buffer property. Reference name
1506;; is button's label
1507(when (>= emacs-major-version 22)
1508 (define-button-type 'markdown-ref-button
1509 'help-echo "Push to create an empty reference definition"
1510 'face 'bold
1511 'action (lambda (b)
1512 (markdown-add-missing-ref-definition
1513 (button-label b) (button-get b 'target-buffer) t))))
1514
1515;; Button jumping to line in buffer specified as its 'target-buffer
1516;; property. Line number is button's 'line property.
1517(when (>= emacs-major-version 22)
1518 (define-button-type 'goto-line-button
1519 'help-echo "Push to go to this line"
1520 'face 'italic
1521 'action (lambda (b)
1522 (message (button-get b 'buffer))
1523 (switch-to-buffer-other-window (button-get b 'target-buffer))
1524 ;; use call-interactively to silence compiler
1525 (call-interactively 'goto-line (button-get b 'target-line)))))
1526
1527(defun markdown-check-refs (&optional silent)
1528 "Show all undefined Markdown references in current `markdown-mode' buffer.
1529
1530If SILENT is non-nil, do not message anything when no undefined
1531references found.
1532
1533Links which have empty reference definitions are considered to be
1534defined."
1535 (interactive "P")
1536 (when (not (eq major-mode 'markdown-mode))
1537 (error "Not available in current mode"))
1538 (let ((oldbuf (current-buffer))
1539 (refs (markdown-get-undefined-refs))
1540 (refbuf (get-buffer-create (replace-regexp-in-string
1541 "%BUFFER%" (buffer-name)
1542 markdown-refcheck-buffer t))))
1543 (if (null refs)
1544 (progn
1545 (when (not silent)
1546 (message "No undefined references found"))
1547 (kill-buffer refbuf))
1548 (with-current-buffer refbuf
1549 (when view-mode
1550 (View-exit-and-edit))
1551 (erase-buffer)
1552 (insert "Following references lack definitions:")
1553 (newline 2)
1554 (dolist (ref refs)
1555 (let ((button-label (format "%s" (car ref))))
1556 (if (>= emacs-major-version 22)
1557 ;; Create a reference button in Emacs 22
1558 (insert-text-button button-label
1559 :type 'markdown-ref-button
1560 'target-buffer oldbuf)
1561 ;; Insert reference as text in Emacs < 22
1562 (insert button-label)))
1563 (insert " (")
1564 (dolist (occurency (cdr ref))
1565 (let ((line (cdr occurency)))
1566 (if (>= emacs-major-version 22)
1567 ;; Create a line number button in Emacs 22
1568 (insert-button (number-to-string line)
1569 :type 'goto-line-button
1570 'target-buffer oldbuf
1571 'target-line line)
1572 ;; Insert line number as text in Emacs < 22
1573 (insert (number-to-string line)))
1574 (insert " "))) (delete-char -1)
1575 (insert ")")
1576 (newline))
1577 (view-buffer-other-window refbuf)
1578 (goto-char (point-min))
1579 (forward-line 2)))))
1580
1581;;; Outline ===================================================================
1582
1583;; The following visibility cycling code was taken from org-mode
1584;; by Carsten Dominik and adapted for markdown-mode.
1585
1586(defvar markdown-cycle-global-status 1)
1587(defvar markdown-cycle-subtree-status nil)
1588
1589;; Based on org-end-of-subtree from org.el
1590(defun markdown-end-of-subtree (&optional invisible-OK)
1591 "Move to the end of the current subtree.
1592Only visible heading lines are considered, unless INVISIBLE-OK is
1593non-nil."
1594 (outline-back-to-heading invisible-OK)
1595 (let ((first t)
1596 (level (funcall outline-level)))
1597 (while (and (not (eobp))
1598 (or first (> (funcall outline-level) level)))
1599 (setq first nil)
1600 (outline-next-heading))
1601 (if (memq (preceding-char) '(?\n ?\^M))
1602 (progn
1603 ;; Go to end of line before heading
1604 (forward-char -1)
1605 (if (memq (preceding-char) '(?\n ?\^M))
1606 ;; leave blank line before heading
1607 (forward-char -1)))))
1608 (point))
1609
1610;; Based on org-cycle from org.el.
1611(defun markdown-cycle (&optional arg)
1612 "Visibility cycling for Markdown mode.
1613If ARG is t, perform global visibility cycling. If the point is
1614at an atx-style header, cycle visibility of the corresponding
1615subtree. Otherwise, insert a tab using `indent-relative'."
1616 (interactive "P")
1617 (cond
1618 ((eq arg t) ;; Global cycling
1619 (cond
1620 ((and (eq last-command this-command)
1621 (eq markdown-cycle-global-status 2))
1622 ;; Move from overview to contents
1623 (hide-sublevels 1)
1624 (message "CONTENTS")
1625 (setq markdown-cycle-global-status 3))
1626
1627 ((and (eq last-command this-command)
1628 (eq markdown-cycle-global-status 3))
1629 ;; Move from contents to all
1630 (show-all)
1631 (message "SHOW ALL")
1632 (setq markdown-cycle-global-status 1))
1633
1634 (t
1635 ;; Defaults to overview
1636 (hide-body)
1637 (message "OVERVIEW")
1638 (setq markdown-cycle-global-status 2))))
1639
1640 ((save-excursion (beginning-of-line 1) (looking-at outline-regexp))
1641 ;; At a heading: rotate between three different views
1642 (outline-back-to-heading)
1643 (let ((goal-column 0) eoh eol eos)
1644 ;; Determine boundaries
1645 (save-excursion
1646 (outline-back-to-heading)
1647 (save-excursion
1648 (beginning-of-line 2)
1649 (while (and (not (eobp)) ;; this is like `next-line'
1650 (get-char-property (1- (point)) 'invisible))
1651 (beginning-of-line 2)) (setq eol (point)))
1652 (outline-end-of-heading) (setq eoh (point))
1653 (markdown-end-of-subtree t)
1654 (skip-chars-forward " \t\n")
1655 (beginning-of-line 1) ; in case this is an item
1656 (setq eos (1- (point))))
1657 ;; Find out what to do next and set `this-command'
1658 (cond
1659 ((= eos eoh)
1660 ;; Nothing is hidden behind this heading
1661 (message "EMPTY ENTRY")
1662 (setq markdown-cycle-subtree-status nil))
1663 ((>= eol eos)
1664 ;; Entire subtree is hidden in one line: open it
1665 (show-entry)
1666 (show-children)
1667 (message "CHILDREN")
1668 (setq markdown-cycle-subtree-status 'children))
1669 ((and (eq last-command this-command)
1670 (eq markdown-cycle-subtree-status 'children))
1671 ;; We just showed the children, now show everything.
1672 (show-subtree)
1673 (message "SUBTREE")
1674 (setq markdown-cycle-subtree-status 'subtree))
1675 (t
1676 ;; Default action: hide the subtree.
1677 (hide-subtree)
1678 (message "FOLDED")
1679 (setq markdown-cycle-subtree-status 'folded)))))
1680
1681 (t
1682 (indent-for-tab-command))))
1683
1684;; Based on org-shifttab from org.el.
1685(defun markdown-shifttab ()
1686 "Global visibility cycling.
1687Calls `markdown-cycle' with argument t."
1688 (interactive)
1689 (markdown-cycle t))
1690
1691;;; Commands ==================================================================
1692
1693(defun markdown (&optional output-buffer-name)
1694 "Run `markdown' on current buffer and insert output in buffer BUFFER-OUTPUT."
1695 (interactive)
1696 (let ((title (buffer-name))
1697 (begin-region)
1698 (end-region))
1699 (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
1700 (setq begin-region (region-beginning)
1701 end-region (region-end))
1702 (setq begin-region (point-min)
1703 end-region (point-max)))
1704
1705 (unless output-buffer-name
1706 (setq output-buffer-name markdown-output-buffer-name))
1707
1708 (if markdown-command-needs-filename
1709 ;; Handle case when `markdown-command' does not read from stdin
1710 (if (not buffer-file-name)
1711 (error "Must be visiting a file")
1712 (shell-command (concat markdown-command " " buffer-file-name)
1713 output-buffer-name))
1714 ;; Pass region to `markdown-command' via stdin
1715 (shell-command-on-region begin-region end-region markdown-command
1716 output-buffer-name))
1717
1718 ;; Add header and footer and switch to html-mode.
1719 (save-current-buffer
1720 (set-buffer output-buffer-name)
1721 (goto-char (point-min))
1722 (unless (markdown-output-standalone-p)
1723 (markdown-add-xhtml-header-and-footer title))
1724 (html-mode))
1725
1726 ;; Ensure buffer gets raised, even with short command output
1727 (switch-to-buffer-other-window output-buffer-name)))
1728
1729(defun markdown-output-standalone-p ()
1730 "Determine whether `markdown-command' output is standalone XHTML.
1731Standalone XHTML output is identified by an occurrence of
1732`markdown-xhtml-standalone-regexp' in the first five lines of output."
1733 (re-search-forward
1734 markdown-xhtml-standalone-regexp
1735 (save-excursion (goto-char (point-min)) (forward-line 4) (point))
1736 t))
1737
1738(defun markdown-add-xhtml-header-and-footer (title)
1739 "Wrap XHTML header and footer with given TITLE around current buffer."
1740 (insert "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
1741 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
1742 "\t\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n"
1743 "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\n"
1744 "<head>\n<title>")
1745 (insert title)
1746 (insert "</title>\n")
1747 (if (> (length markdown-css-path) 0)
1748 (insert "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\""
1749 markdown-css-path
1750 "\" />\n"))
1751 (when (> (length markdown-xhtml-header-content) 0)
1752 (insert markdown-xhtml-header-content))
1753 (insert "\n</head>\n\n"
1754 "<body>\n\n")
1755 (goto-char (point-max))
1756 (insert "\n"
1757 "</body>\n"
1758 "</html>\n"))
1759
1760(defun markdown-preview ()
1761 "Run `markdown' on the current buffer and preview the output in a browser."
1762 (interactive)
1763 (markdown markdown-output-buffer-name)
1764 (browse-url-of-buffer markdown-output-buffer-name))
1765
1766(defun markdown-export-file-name ()
1767 "Attempt to generate a filename for Markdown output.
1768If the current buffer is visiting a file, we construct a new
1769output filename based on that filename. Otherwise, return nil."
1770 (when (buffer-file-name)
1771 (concat (file-name-sans-extension (buffer-file-name)) ".html")))
1772
1773(defun markdown-export ()
1774 "Run Markdown on the current buffer, save to a file, and return the filename.
1775The resulting filename will be constructed using the current filename, but
1776with the extension removed and replaced with .html."
1777 (interactive)
1778 (let ((output-file (markdown-export-file-name))
1779 (output-buffer-name))
1780 (when output-file
1781 (setq output-buffer-name (buffer-name (find-file-noselect output-file)))
1782 (markdown output-buffer-name)
1783 (with-current-buffer output-buffer-name
1784 (save-buffer)
1785 (kill-buffer-and-window))
1786 output-file)))
1787
1788(defun markdown-export-and-view ()
1789 "Export to XHTML using `markdown-export' and browse the resulting file."
1790 (interactive)
1791 (browse-url (markdown-export)))
1792
1793;;; WikiLink Following/Markup =================================================
1794
1795(require 'thingatpt)
1796
1797(defun markdown-wiki-link-p ()
1798 "Return non-nil when `point' is at a true wiki link.
1799A true wiki link name matches `markdown-regex-wiki-link' but does not
1800match the current file name after conversion. This modifies the data
1801returned by `match-data'. Note that the potential wiki link name must
1802be available via `match-string'."
1803 (let ((case-fold-search nil))
1804 (and (thing-at-point-looking-at markdown-regex-wiki-link)
1805 (or (not buffer-file-name)
1806 (not (string-equal (buffer-file-name)
1807 (markdown-convert-wiki-link-to-filename
1808 (match-string 1)))))
1809 (not (save-match-data
1810 (save-excursion))))))
1811
1812(defun markdown-convert-wiki-link-to-filename (name)
1813 "Generate a filename from the wiki link NAME.
1814Spaces are converted to underscores, following the convention
1815used by the Python Markdown WikiLinks extension."
1816 (let ((new-ext (file-name-extension (buffer-file-name)))
1817 (new-basename (replace-regexp-in-string "[[:space:]\n]" "_" name)))
1818 (concat new-basename "." new-ext)))
1819
1820(defun markdown-follow-wiki-link (name)
1821 "Follow the wiki link NAME.
1822Convert the name to a file name and call `find-file'. Ensure that
1823the new buffer remains in `markdown-mode'."
1824 (let ((filename (markdown-convert-wiki-link-to-filename name)))
1825 (find-file filename))
1826 (markdown-mode))
1827
1828(defun markdown-follow-wiki-link-at-point ()
1829 "Find Wiki Link at point.
1830See `markdown-wiki-link-p' and `markdown-follow-wiki-link'."
1831 (interactive)
1832 (if (markdown-wiki-link-p)
1833 (markdown-follow-wiki-link (match-string 1))
1834 (error "Point is not at a Wiki Link")))
1835
1836(defun markdown-next-wiki-link ()
1837 "Jump to next wiki link.
1838See `markdown-wiki-link-p'."
1839 (interactive)
1840 (if (markdown-wiki-link-p)
1841 ; At a wiki link already, move past it.
1842 (goto-char (+ 1 (match-end 0))))
1843 (save-match-data
1844 ; Search for the next wiki link and move to the beginning.
1845 (re-search-forward markdown-regex-wiki-link nil t)
1846 (goto-char (match-beginning 0))))
1847
1848(defun markdown-previous-wiki-link ()
1849 "Jump to previous wiki link.
1850See `markdown-wiki-link-p'."
1851 (interactive)
1852 (re-search-backward markdown-regex-wiki-link nil t))
1853
1854(defun markdown-highlight-wiki-link (from to face)
1855 "Highlight the wiki link in the region between FROM and TO using FACE."
1856 (let ((ov (make-overlay from to)))
1857 (overlay-put ov 'face face)))
1858
1859(defun markdown-unfontify-region-wiki-links (from to)
1860 "Remove wiki link faces from the region specified by FROM and TO."
1861 (interactive "nfrom: \nnto: ")
1862 (remove-overlays from to 'face markdown-link-face)
1863 (remove-overlays from to 'face markdown-missing-link-face))
1864
1865(defun markdown-fontify-region-wiki-links (from to)
1866 "Search region given by FROM and TO for wiki links and fontify them.
1867If a wiki link is found check to see if the backing file exists
1868and highlight accordingly."
1869 (goto-char from)
1870 (while (re-search-forward markdown-regex-wiki-link to t)
1871 (let ((highlight-beginning (match-beginning 0))
1872 (highlight-end (match-end 0))
1873 (file-name
1874 (markdown-convert-wiki-link-to-filename (match-string 1))))
1875 (if (file-exists-p file-name)
1876 (markdown-highlight-wiki-link
1877 highlight-beginning highlight-end markdown-link-face)
1878 (markdown-highlight-wiki-link
1879 highlight-beginning highlight-end markdown-missing-link-face)))))
1880
1881(defun markdown-extend-changed-region (from to)
1882 "Extend region given by FROM and TO so that we can fontify all links.
1883The region is extended to the first newline before and the first
1884newline after."
1885 ;; start looking for the first new line before 'from
1886 (goto-char from)
1887 (re-search-backward "\n" nil t)
1888 (let ((new-from (point-min))
1889 (new-to (point-max)))
1890 (if (not (= (point) from))
1891 (setq new-from (point)))
1892 ;; do the same thing for the first new line after 'to
1893 (goto-char to)
1894 (re-search-forward "\n" nil t)
1895 (if (not (= (point) to))
1896 (setq new-to (point)))
1897 (list new-from new-to)))
1898
1899(defun markdown-check-change-for-wiki-link (from to change)
1900 "Check region between FROM and TO for wiki links and re-fontfy as needed.
1901Designed to be used with the `after-change-functions' hook.
1902CHANGE is the number of bytes of pre-change text replaced by the
1903given range."
1904 (interactive "nfrom: \nnto: \nnchange: ")
1905 (let* ((inhibit-point-motion-hooks t)
1906 (inhibit-quit t)
1907 (modified (buffer-modified-p))
1908 (buffer-undo-list t)
1909 (inhibit-read-only t)
1910 (inhibit-point-motion-hooks t)
1911 (inhibit-modification-hooks t)
1912 (current-point (point))
1913 deactivate-mark)
1914 (unwind-protect
1915 (save-restriction
1916 ;; Extend the region to fontify so that it starts
1917 ;; and ends at safe places.
1918 (multiple-value-bind (new-from new-to)
1919 (markdown-extend-changed-region from to)
1920 ;; Unfontify existing fontification (start from scratch)
1921 (markdown-unfontify-region-wiki-links new-from new-to)
1922 ;; Now do the fontification.
1923 (markdown-fontify-region-wiki-links new-from new-to)))
1924 (unless modified
1925 (restore-buffer-modified-p nil)))
1926 (goto-char current-point)))
1927
1928(defun markdown-fontify-buffer-wiki-links ()
1929 "Refontify all wiki links in the buffer."
1930 (interactive)
1931 (markdown-check-change-for-wiki-link (point-min) (point-max) 0))
1932
1933;;; Miscellaneous =============================================================
1934
1935(defun markdown-line-number-at-pos (&optional pos)
1936 "Return (narrowed) buffer line number at position POS.
1937If POS is nil, use current buffer location.
1938This is an exact copy of `line-number-at-pos' for use in emacs21."
1939 (let ((opoint (or pos (point))) start)
1940 (save-excursion
1941 (goto-char (point-min))
1942 (setq start (point))
1943 (goto-char opoint)
1944 (forward-line 0)
1945 (1+ (count-lines start (point))))))
1946
1947(defun markdown-nobreak-p ()
1948 "Return nil if it is acceptable to break the current line at the point."
1949 ;; inside in square brackets (e.g., link anchor text)
1950 (looking-back "\\[[^]]*"))
1951
1952
1953
1954;;; Mode definition ==========================================================
1955
1956(defun markdown-show-version ()
1957 "Show the version number in the minibuffer."
1958 (interactive)
1959 (message "markdown-mode, version %s" markdown-mode-version))
1960
1961;;;###autoload
1962(define-derived-mode markdown-mode text-mode "Markdown"
1963 "Major mode for editing Markdown files."
1964 ;; Natural Markdown tab width
1965 (setq tab-width 4)
1966 ;; Comments
1967 (make-local-variable 'comment-start)
1968 (setq comment-start "<!-- ")
1969 (make-local-variable 'comment-end)
1970 (setq comment-end " -->")
1971 (make-local-variable 'comment-start-skip)
1972 (setq comment-start-skip "<!--[ \t]*")
1973 (make-local-variable 'comment-column)
1974 (setq comment-column 0)
1975 ;; Font lock.
1976 (set (make-local-variable 'font-lock-defaults)
1977 '(markdown-mode-font-lock-keywords))
1978 (set (make-local-variable 'font-lock-multiline) t)
1979 ;; For menu support in XEmacs
1980 (easy-menu-add markdown-mode-menu markdown-mode-map)
1981 ;; Make filling work with lists (unordered, ordered, and definition)
1982 (set (make-local-variable 'paragraph-start)
1983 "\f\\|[ \t]*$\\|^[ \t]*[*+-] \\|^[ \t*][0-9]+\\.\\|^[ \t]*: ")
1984 ;; Outline mode
1985 (make-local-variable 'outline-regexp)
1986 (setq outline-regexp "#+")
1987 ;; Cause use of ellipses for invisible text.
1988 (add-to-invisibility-spec '(outline . t))
1989 ;; Indentation and filling
1990 (make-local-variable 'fill-nobreak-predicate)
1991 (add-hook 'fill-nobreak-predicate 'markdown-nobreak-p)
1992 (setq indent-line-function markdown-indent-function)
1993
1994 ;; Prepare hooks for XEmacs compatibility
1995 (when (featurep 'xemacs)
1996 (make-local-hook 'after-change-functions)
1997 (make-local-hook 'font-lock-extend-region-functions)
1998 (make-local-hook 'window-configuration-change-hook))
1999
2000 ;; Multiline font lock
2001 (add-hook 'font-lock-extend-region-functions
2002 'markdown-font-lock-extend-region)
2003
2004 ;; Anytime text changes make sure it gets fontified correctly
2005 (add-hook 'after-change-functions 'markdown-check-change-for-wiki-link t t)
2006
2007 ;; If we left the buffer there is a really good chance we were
2008 ;; creating one of the wiki link documents. Make sure we get
2009 ;; refontified when we come back.
2010 (add-hook 'window-configuration-change-hook
2011 'markdown-fontify-buffer-wiki-links t t)
2012
2013 ;; do the initial link fontification
2014 (markdown-fontify-buffer-wiki-links))
2015
2016;(add-to-list 'auto-mode-alist '("\\.text$" . markdown-mode))
2017
2018;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2019;;; Kuzzooroo's code for handling Markdown links
2020
2021(defun markdown-linkd-follow-at-point ()
2022 "Follow the link at point."
2023 (interactive)
2024 (loop for ov in (overlays-at (point)) do
2025 (let ((url (overlay-get ov 'markdown-linkd-url)))
2026 (when url
2027 (browse-url url)))))
2028
2029(defun markdown-linkd-follow-mouse (event)
2030 "Follow the clicked link."
2031 (interactive "e")
2032 (when event
2033 (select-window (posn-window (event-start event)))
2034 (set-buffer (window-buffer (posn-window (event-start event))))
2035 (goto-char (posn-point (event-start event)))
2036 (markdown-linkd-follow-at-point)))
2037
2038
2039(defvar markdown-linkd-overlay-map nil "Keymap for Linkd overlays.")
2040(unless markdown-linkd-overlay-map
2041 (setq markdown-linkd-overlay-map (make-sparse-keymap))
2042 (define-key markdown-linkd-overlay-map (kbd "RET")
2043 'markdown-linkd-follow-at-point)
2044 (define-key markdown-linkd-overlay-map [mouse-2] 'markdown-linkd-follow-mouse))
2045
2046(defun markdown-linkd-overlay-at-p (loc)
2047 (loop for ov in (overlays-at loc)
2048 thereis (overlay-get ov 'markdown-linkd-url)))
2049
2050(defun markdown-linkd-render-link (link-beg link-end url-beg url-end display-face)
2051 ;; It's not enough to mark links with a text property because text properties get copied and overlays do not
2052 (unless (markdown-linkd-overlay-at-p link-beg)
2053 (let ((url (buffer-substring-no-properties (1+ url-beg) (1- url-end)))
2054 (display-text (concat
2055 (buffer-substring-no-properties link-beg link-end)
2056 "()")))
2057 (markdown-linkd-overlay link-beg url-end url display-text display-face))))
2058
2059(defun markdown-linkd-overlay (beg end url display-text display-face)
2060 "Apply Linkd overlay to link text"
2061 (let ((overlay (make-overlay beg end))
2062 (overlay-modification-code
2063 (list (lambda (ov foo beg end &rest ignore)
2064 (delete-overlay ov)
2065 ))))
2066 (overlay-put
2067 ;; Could maybe use invisible text rather than display-text, but this
2068 ;; way makes it easy to also get a live link with a single overlay
2069 overlay 'display (propertize display-text
2070 'face display-face
2071 'keymap markdown-linkd-overlay-map)) ; add speed-navigation keys
2072 (overlay-put overlay 'mouse-face 'highlight)
2073 (overlay-put overlay 'keymap markdown-linkd-overlay-map) ; add speed-navigation keys
2074 (overlay-put overlay 'evaporate t)
2075 (overlay-put overlay 'markdown-linkd-url url)
2076 (overlay-put overlay 'modification-hooks overlay-modification-code)
2077 (overlay-put overlay 'insert-in-front-hooks overlay-modification-code)
2078 (overlay-put overlay 'insert-behind-hooks overlay-modification-code)))
2079
2080;; Sometimes reverting a file confuses my markdown-linkd stuff. This is
2081;; a heavy-handed attempt to solve the problem
2082(add-hook 'after-revert-hook 'remove-overlays)
2083
2084;;; GitHub Flavored Markdown Mode ============================================
2085
2086(define-derived-mode gfm-mode markdown-mode "GFM"
2087 "Major mode for editing GitHub Flavored Markdown files."
2088 (auto-fill-mode 0)
2089 (longlines-mode 1))
2090
2091(provide 'markdown-mode)
2092
2093;;; markdown-mode.el ends here