           (setq markdown-cycle-subtree-status 'folded)))))
 
      (t
-      (message "TAB")
-      (indent-relative))))
+      (indent-for-tab-command))))
 
 ;; Based on org-shifttab from org.el.
-(defun markdown-shifttab (&optional arg)
-  "Global visibility cycling or move to previous table field.
-Calls `markdown-cycle' with argument t"
-  (interactive "P")
+(defun markdown-shifttab ()
+  "Global visibility cycling.
+Calls `markdown-cycle' with argument t."
+  (interactive)
   (markdown-cycle t))
 
 ;;; Commands ==================================================================
 
-(defun markdown ()
-  "Run markdown on the current buffer and preview the output in another buffer."
-  (interactive)
+(defun markdown (&optional output-buffer-name)
+  "Run `markdown' on current buffer and insert output in buffer BUFFER-OUTPUT."
+  (interactive)
+  (let ((title (buffer-name))
+        (begin-region)
+        (end-region))
     (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
-        (shell-command-on-region (region-beginning) (region-end) markdown-command
-                                 "*markdown-output*" nil)
-      (shell-command-on-region (point-min) (point-max) markdown-command
-                               "*markdown-output*" nil)))
+        (setq begin-region (region-beginning)
+              end-region (region-end))
+      (setq begin-region (point-min)
+            end-region (point-max)))
+
+    (unless output-buffer-name
+      (setq output-buffer-name markdown-output-buffer-name))
+
+    (if markdown-command-needs-filename
+        ;; Handle case when `markdown-command' does not read from stdin
+        (if (not buffer-file-name)
+            (error "Must be visiting a file")
+          (shell-command (concat markdown-command " " buffer-file-name)
+                         output-buffer-name))
+      ;; Pass region to `markdown-command' via stdin
+      (shell-command-on-region begin-region end-region markdown-command
+                               output-buffer-name))
+
+    ;; Add header and footer and switch to html-mode.
+    (save-current-buffer
+      (set-buffer output-buffer-name)
+      (goto-char (point-min))
+      (unless (markdown-output-standalone-p)
+        (markdown-add-xhtml-header-and-footer title))
+      (html-mode))
+
+    ;; Ensure buffer gets raised, even with short command output
+    (switch-to-buffer-other-window output-buffer-name)))
+
+(defun markdown-output-standalone-p ()
+  "Determine whether `markdown-command' output is standalone XHTML.
+Standalone XHTML output is identified by an occurrence of
+`markdown-xhtml-standalone-regexp' in the first five lines of output."
+  (re-search-forward
+   markdown-xhtml-standalone-regexp
+   (save-excursion (goto-char (point-min)) (forward-line 4) (point))
+   t))
+
+(defun markdown-add-xhtml-header-and-footer (title)
+  "Wrap XHTML header and footer with given TITLE around current buffer."
+  (insert "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+          "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
+          "\t\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n"
+          "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\n"
+          "<head>\n<title>")
+  (insert title)
+  (insert "</title>\n")
+  (if (> (length markdown-css-path) 0)
+      (insert "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\""
+              markdown-css-path
+              "\"  />\n"))
+  (when (> (length markdown-xhtml-header-content) 0)
+    (insert markdown-xhtml-header-content))
+  (insert "\n</head>\n\n"
+          "<body>\n\n")
+  (goto-char (point-max))
+  (insert "\n"
+          "</body>\n"
+          "</html>\n"))
 
 (defun markdown-preview ()
-  "Run markdown on the current buffer and preview the output in a browser."
-  (interactive)
-  (markdown)
-  (browse-url-of-buffer "*markdown-output*"))
-
+  "Run `markdown' on the current buffer and preview the output in a browser."
+  (interactive)
+  (markdown markdown-output-buffer-name)
+  (browse-url-of-buffer markdown-output-buffer-name))
+
+(defun markdown-export-file-name ()
+  "Attempt to generate a filename for Markdown output.
+If the current buffer is visiting a file, we construct a new
+output filename based on that filename.  Otherwise, return nil."
+  (when (buffer-file-name)
+    (concat (file-name-sans-extension (buffer-file-name)) ".html")))
+
+(defun markdown-export ()
+  "Run Markdown on the current buffer, save to a file, and return the filename.
+The resulting filename will be constructed using the current filename, but
+with the extension removed and replaced with .html."
+  (interactive)
+  (let ((output-file (markdown-export-file-name))
+        (output-buffer-name))
+    (when output-file
+      (setq output-buffer-name (buffer-name (find-file-noselect output-file)))
+      (markdown output-buffer-name)
+      (with-current-buffer output-buffer-name
+        (save-buffer)
+        (kill-buffer-and-window))
+      output-file)))
+
+(defun markdown-export-and-view ()
+  "Export to XHTML using `markdown-export' and browse the resulting file."
+  (interactive)
+  (browse-url (markdown-export)))
+
+;;; WikiLink Following/Markup =================================================
+
+(require 'thingatpt)
+
+(defun markdown-wiki-link-p ()
+  "Return non-nil when `point' is at a true wiki link.
+A true wiki link name matches `markdown-regex-wiki-link' but does not
+match the current file name after conversion.  This modifies the data
+returned by `match-data'.  Note that the potential wiki link name must
+be available via `match-string'."
+  (let ((case-fold-search nil))
+    (and (thing-at-point-looking-at markdown-regex-wiki-link)
+	 (or (not buffer-file-name)
+	     (not (string-equal (buffer-file-name)
+				(markdown-convert-wiki-link-to-filename
+				 (match-string 1)))))
+	 (not (save-match-data
+		(save-excursion))))))
+
+(defun markdown-convert-wiki-link-to-filename (name)
+  "Generate a filename from the wiki link NAME.
+Spaces are converted to underscores, following the convention
+used by the Python Markdown WikiLinks extension."
+  (let ((new-ext (file-name-extension (buffer-file-name)))
+	(new-basename (replace-regexp-in-string "[[:space:]\n]" "_" name)))
+    (concat new-basename "." new-ext)))
+
+(defun markdown-follow-wiki-link (name)
+  "Follow the wiki link NAME.
+Convert the name to a file name and call `find-file'.  Ensure that
+the new buffer remains in `markdown-mode'."
+  (let ((filename (markdown-convert-wiki-link-to-filename name)))
+    (find-file filename))
+  (markdown-mode))
+
+(defun markdown-follow-wiki-link-at-point ()
+  "Find Wiki Link at point.
+See `markdown-wiki-link-p' and `markdown-follow-wiki-link'."
+  (interactive)
+  (if (markdown-wiki-link-p)
+      (markdown-follow-wiki-link (match-string 1))
+    (error "Point is not at a Wiki Link")))
+
+(defun markdown-next-wiki-link ()
+  "Jump to next wiki link.
+See `markdown-wiki-link-p'."
+  (interactive)
+  (if (markdown-wiki-link-p)
+      ; At a wiki link already, move past it.
+      (goto-char (+ 1 (match-end 0))))
+  (save-match-data
+    ; Search for the next wiki link and move to the beginning.
+    (re-search-forward markdown-regex-wiki-link nil t)
+    (goto-char (match-beginning 0))))
+
+(defun markdown-previous-wiki-link ()
+  "Jump to previous wiki link.
+See `markdown-wiki-link-p'."
+  (interactive)
+  (re-search-backward markdown-regex-wiki-link nil t))
+
+(defun markdown-highlight-wiki-link (from to face)
+  "Highlight the wiki link in the region between FROM and TO using FACE."
+  (let ((ov (make-overlay from to)))
+    (overlay-put ov 'face face)))
+
+(defun markdown-unfontify-region-wiki-links (from to)
+  "Remove wiki link faces from the region specified by FROM and TO."
+  (interactive "nfrom: \nnto: ")
+  (remove-overlays from to 'face markdown-link-face)
+  (remove-overlays from to 'face markdown-missing-link-face))
+
+(defun markdown-fontify-region-wiki-links (from to)
+  "Search region given by FROM and TO for wiki links and fontify them.
+If a wiki link is found check to see if the backing file exists
+and highlight accordingly."
+  (goto-char from)
+  (while (re-search-forward markdown-regex-wiki-link to t)
+    (let ((highlight-beginning (match-beginning 0))
+	  (highlight-end (match-end 0))
+	  (file-name
+	   (markdown-convert-wiki-link-to-filename (match-string 1))))
+      (if (file-exists-p file-name)
+	  (markdown-highlight-wiki-link
+	   highlight-beginning highlight-end markdown-link-face)
+	(markdown-highlight-wiki-link
+	 highlight-beginning highlight-end markdown-missing-link-face)))))
+
+(defun markdown-extend-changed-region (from to)
+  "Extend region given by FROM and TO so that we can fontify all links.
+The region is extended to the first newline before and the first
+newline after."
+  ;; start looking for the first new line before 'from
+  (goto-char from)
+  (re-search-backward "\n" nil t)
+  (let ((new-from (point-min))
+	(new-to (point-max)))
+    (if (not (= (point) from))
+	(setq new-from (point)))
+    ;; do the same thing for the first new line after 'to
+    (goto-char to)
+    (re-search-forward "\n" nil t)
+    (if (not (= (point) to))
+	(setq new-to (point)))
+    (list new-from new-to)))
+
+(defun markdown-check-change-for-wiki-link (from to change)
+  "Check region between FROM and TO for wiki links and re-fontfy as needed.
+Designed to be used with the `after-change-functions' hook.
+CHANGE is the number of bytes of pre-change text replaced by the
+given range."
+  (interactive "nfrom: \nnto: \nnchange: ")
+  (let* ((inhibit-point-motion-hooks t)
+	 (inhibit-quit t)
+	 (modified (buffer-modified-p))
+	 (buffer-undo-list t)
+	 (inhibit-read-only t)
+	 (inhibit-point-motion-hooks t)
+	 (inhibit-modification-hooks t)
+	 (current-point (point))
+	 deactivate-mark)
+    (unwind-protect
+	(save-restriction
+	  ;; Extend the region to fontify so that it starts
+	  ;; and ends at safe places.
+	  (multiple-value-bind (new-from new-to)
+	      (markdown-extend-changed-region from to)
+	    ;; Unfontify existing fontification (start from scratch)
+	    (markdown-unfontify-region-wiki-links new-from new-to)
+	    ;; Now do the fontification.
+	    (markdown-fontify-region-wiki-links new-from new-to)))
+      (unless modified
+	(restore-buffer-modified-p nil)))
+    (goto-char current-point)))
+
+(defun markdown-fontify-buffer-wiki-links ()
+  "Refontify all wiki links in the buffer."
+  (interactive)
+  (markdown-check-change-for-wiki-link (point-min) (point-max) 0))
 
 ;;; Miscellaneous =============================================================
 
 (defun markdown-line-number-at-pos (&optional pos)
   "Return (narrowed) buffer line number at position POS.
 If POS is nil, use current buffer location.
-This is an exact copy of line-number-at-pos for use in emacs21."
+This is an exact copy of `line-number-at-pos' for use in emacs21."
   (let ((opoint (or pos (point))) start)
     (save-excursion
       (goto-char (point-min))

  :group 'markdown
  :type 'boolean)


;;; Font lock =================================================================

(require 'font-lock)

(defgroup markdown-faces nil
  "Faces used in Markdown Mode"
  :group 'markdown
  :group 'faces)

(defcustom markdown-italic-face 'font-lock-variable-name-face
  "Italic text."
  :group 'markdown-faces
  :type '(face))

(defcustom markdown-bold-face 'font-lock-type-face
  "Bold text"
  :group 'markdown-faces
  :type '(face))

(defcustom markdown-header-face 'font-lock-function-name-face
  "Headers"
  :group 'markdown-faces
  :type '(face))

(defcustom markdown-inline-code-face 'font-lock-builtin-face
  "Inline code"
  :group 'markdown-faces
  :type '(face))

(defcustom markdown-list-face 'font-lock-variable-name-face
  "List item markers"
  :group 'markdown-faces
  :type '(face))

(defcustom markdown-blockquote-face 'font-lock-comment-face
  "Blockquote sections and preformatted text"
  :group 'markdown-faces
  :type '(face))

(defcustom markdown-link-face 'font-lock-constant-face
  "Link text"
  :group 'markdown-faces
  :type '(face))

(defcustom markdown-reference-face 'font-lock-type-face
  "Link references"
  :group 'markdown-faces
  :type '(face))

(defcustom markdown-url-face 'font-lock-string-face
  "URLs"
  :group 'markdown-faces
  :type '(face))

(defcustom markdown-math-face 'font-lock-builtin-face
  "LaTeX expressions"
  :group 'markdown-faces
  :type '(face))

(defconst markdown-regex-link-inline
  "\\(!?\\[[^]]*?\\]\\)\\(([^\\)]*)\\)"
  "Regular expression for a [text](file) or an image link ![text](file)")

(defconst markdown-regex-link-reference
  "\\(!?\\[[^]]+?\\]\\)[ ]?\\(\\[[^]]*?\\]\\)"
  "Regular expression for a reference link [text][id]")

(defconst markdown-regex-reference-definition
  "^ \\{0,3\\}\\(\\[.+?\\]\\):\\s *\\(.*?\\)\\s *\\( \"[^\"]*\"$\\|$\\)"
  "Regular expression for a link definition [id]: ...")

(defconst markdown-regex-header-atx
  "^\\(#+ \\)\\(.*?\\)\\($\\| #+$\\)"
  "Regular expression for atx-style (hash mark) headers")

(defconst markdown-regex-header-setext
  "^\\(.*\\)\n\\(===+\\|---+\\)$"
  "Regular expression for setext-style (underline) headers")

(defconst markdown-regex-hr
  "^\\(\\*[ ]?\\*[ ]?\\*[ ]?[\\* ]*\\|-[ ]?-[ ]?-[--- ]*\\)$"
  "Regular expression for matching Markdown horizontal rules")

(defconst markdown-regex-code
  "\\(^\\|[^\\]\\)\\(\\(`\\{1,2\\}\\)\\([^ \\]\\|[^ ].*?[^ \\]\\)\\3\\)"
  "Regular expression for matching inline code fragments")

(defconst markdown-regex-pre
  "^    .*$"
  "Regular expression for matching preformatted text sections")

(defconst markdown-regex-list
  "^[ \t]*\\([0-9]+\\.\\|[\\*\\+-]\\) "
  "Regular expression for matching list markers")

(defconst markdown-regex-bold
  "\\(^\\|[^\\]\\)\\(\\([*_]\\{2\\}\\)\\(.\\|\n\\)*?[^\\ ]\\3\\)"
  "Regular expression for matching bold text")

(defconst markdown-regex-italic
  "\\(^\\|[^\\]\\)\\(\\([*_]\\)\\([^ \\]\\3\\|[^ ]\\(.\\|\n\\)*?[^\\ ]\\3\\)\\)"
  "Regular expression for matching italic text")

(defconst markdown-regex-blockquote
  "^>.*$"
  "Regular expression for matching blockquote lines")

(defconst markdown-regex-line-break
  "  $"
  "Regular expression for matching line breaks")

(defconst markdown-regex-wiki-link
  "\\[\\[[^]]+\\]\\]"
  "Regular expression for matching wiki links")

(defconst markdown-regex-uri
  "<\\(acap\\|cid\\|data\\|dav\\|fax\\|file\\|ftp\\|gopher\\|http\\|https\\|imap\\|ldap\\|mailto\\|mid\\|modem\\|news\\|nfs\\|nntp\\|pop\\|prospero\\|rtsp\\|service\\|sip\\|tel\\|telnet\\|tip\\|urn\\|vemmi\\|wais\\)://[^>]*>"
  "Regular expression for matching inline URIs")

(defconst markdown-regex-email
  "<\\(\\sw\\|\\s_\\|\\s.\\)+@\\(\\sw\\|\\s_\\|\\s.\\)+>"
  "Regular expression for matching inline email addresses")

(defconst markdown-regex-latex-expression
  "\\(^\\|[^\\]\\)\\(\\$\\($\\([^\\$]\\|\\\\.\\)*\\$\\|\\([^\\$]\\|\\\\.\\)*\\)\\$\\)"
  "Regular expression for itex $..$ or $$..$$ math mode expressions")

(defconst markdown-regex-latex-display
    "^\\\\\\[\\(.\\|\n\\)*?\\\\\\]$"
  "Regular expression for itex \[..\] display mode expressions")

(defconst markdown-mode-font-lock-keywords-basic
  (list
   (cons markdown-regex-code '(2 markdown-inline-code-face))
   (cons markdown-regex-pre markdown-blockquote-face)
   (cons markdown-regex-header-setext markdown-header-face)
   (cons markdown-regex-header-atx markdown-header-face)
   (cons markdown-regex-list markdown-list-face)
   (cons markdown-regex-hr markdown-header-face)
   (cons markdown-regex-link-inline
         '((1 markdown-link-face t)
           (2 markdown-url-face t)))

    'action (lambda (b)
              (message (button-get b 'buffer))
              (switch-to-buffer-other-window (button-get b 'target-buffer))
              ;; use call-interactively to silence compiler
              (call-interactively 'goto-line (button-get b 'target-line)))))

(defun markdown-check-refs (&optional silent)
  "Show all undefined Markdown references in current `markdown-mode' buffer.
