changeset 71:ca6e4eda3dca

Add more packages
author Jordi Gutiérrez Hermoso <jordigh@octave.org>
date Mon, 06 Aug 2012 12:23:17 -0400
parents b21179c7b441
children b086e0144b71
files packages/coffee.el packages/csv-mode.el packages/graphviz-dot-mode.el packages/markdown-mode.el
diffstat 4 files changed, 3789 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/coffee.el
@@ -0,0 +1,114 @@
+;;; coffee.el --- Submit a BREW request to an RFC2324-compliant coffee device
+;;;
+;;; Author: Eric Marsden <emarsden@laas.fr>
+;;; Version: 0.3
+;;; Copyright: (C) 1999, 2003 Eric Marsden
+;;; Keywords: coffee, brew, kitchen-sink, can't
+;;
+;;     This program is free software; you can redistribute it and/or
+;;     modify it under the terms of the GNU General Public License as
+;;     published by the Free Software Foundation; either version 2 of
+;;     the License, or (at your option) any later version.
+;;     
+;;     This program is distributed in the hope that it will be useful,
+;;     but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;     GNU General Public License for more details.
+;;     
+;;     You should have received a copy of the GNU General Public
+;;     License along with this program; if not, write to the Free
+;;     Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+;;     MA 02111-1307, USA.
+;;
+;; Please send suggestions and bug reports to <emarsden@laas.fr>. 
+;; The latest version of this package should be available at
+;;
+;;     <URL:http://purl.org/net/emarsden/home/downloads/>
+
+;;; Commentary:
+;;
+;; This module provides an Emacs interface to RFC2324-compliant coffee
+;; devices (Hyper Text Coffee Pot Control Protocol, or HTCPCP). It
+;; prompts the user for the different additives, then issues a BREW
+;; request to the coffee device.
+;;
+;; coffee.el requires a special BREW-capable version of Emacs/W3 to be
+;; installed.
+;;
+;; Reference: <URL:ftp://ftp.isi.edu/in-notes/rfc2324.txt>
+;;
+;;
+;; Thanks to Giacomo Boffi <giacomo.boffi@polimi.it> for some typos
+;; and the addition of the "Brown-Coffee" sweetener type.
+
+;;; Code:
+
+(require 'cl)
+
+(defvar coffee-host "coffee"
+  "*The host which provides the coffee service.") 
+
+(defvar coffee-pot-designator 1
+  "*On machines with multiple pots, the number of the pot to brew in")
+
+(defvar coffee-brew-hook nil
+  "*Hook executed before issuing a BREW request")
+
+(defconst coffee-milk-types
+  '("Cream" "Half-and-Half" "Whole-Milk" "Part-Skim" "Skim" "Non-Dairy"))
+
+(defconst coffee-syrup-types '("Vanilla" "Almond" "Raspberry" "Chocolate"))
+
+(defconst coffee-sweetener-types '("White-Sugar" "Brown-Sugar" "Artificial-Sweetener"))
+
+(defconst coffee-alcohol-types '("Whiskey" "Rum" "Kahula" "Aquavit"))
+
+(defconst coffee-addition-types
+  `(("Milk"      . ,coffee-milk-types)
+    ("Syrup"     . ,coffee-syrup-types)
+    ("Sweetener" . ,coffee-sweetener-types)
+    ("Alcohol"   . ,coffee-alcohol-types)))
+
+(defun coffee ()
+  "Submit a BREW request to an RFC2324-compliant coffee device"
+  (interactive)
+  (require 'url)
+  (let* ((additions-list
+          (append coffee-milk-types
+                  coffee-syrup-types
+                  coffee-sweetener-types
+                  coffee-alcohol-types))
+         (additions-string
+          (mapconcat #'identity additions-list ","))
+         (url (coffee-url))
+         (url-request-method "BREW")
+         (url-request-extra-headers
+          `(("Content-type"     . "message-coffeepot")
+            ("Accept-Additions" . ,additions-string)))
+         (url-request-data "START"))
+    (run-hooks 'coffee-brew-hook)
+    (url-retrieve url (lambda () (coffee-drink)))))
+
+(defun coffee-additions ()
+  (let* ((type-name
+          (completing-read "Coffee addition: " coffee-addition-types nil t))
+         (type (cdr (assoc type-name coffee-addition-types)))
+         (ingredients (mapcar #'(lambda (a) (cons a a)) type))
+         (ingredient
+          (completing-read "Addition type: " ingredients nil t)))
+    ingredient))
+
+(defun coffee-url ()
+  (require 'w3-forms)
+  (concat "coffee://" coffee-host "/"
+          (int-to-string coffee-pot-designator)
+          "?" (w3-form-encode-xwfu (coffee-additions))))
+
+
+(defun coffee-drink ()
+  (sleep-for -1))
+
+
+(provide 'coffee)
+
+;; coffee.el ends here
new file mode 100644
--- /dev/null
+++ b/packages/csv-mode.el
@@ -0,0 +1,1286 @@
+;;; csv-mode.el --- major mode for editing comma-separated value files
+
+;; Copyright (C) 2003, 2004 Francis J. Wright
+
+;; Author: Francis J. Wright <F.J.Wright at qmul.ac.uk>
+;; Time-stamp: <23 August 2004>
+;; URL: http://centaur.maths.qmul.ac.uk/Emacs/
+;; Version: $Id: csv-mode.el,v 1.1 2005/09/28 01:52:41 psg Exp $
+;; Keywords: convenience
+
+;; This file is not part of GNU Emacs.
+
+;; This package is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; This package is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This package is intended for use with GNU Emacs 21 (only) and
+;; implements the following commands to process records of CSV
+;; (comma-separated value) type: `csv-sort-fields' and
+;; `csv-sort-numeric-fields' sort respectively lexicographically and
+;; numerically on a specified field or column; `csv-reverse-region'
+;; reverses the order.  They are based closely on, and use, code in
+;; `sort.el'.  `csv-kill-fields' and `csv-yank-fields' respectively
+;; kill and yank fields or columns, although they do not use the
+;; normal kill ring.  `csv-kill-fields' can kill more than one field
+;; at once, but multiple killed fields can be yanked only as a fixed
+;; group equivalent to a single field.  `csv-align-fields' aligns
+;; fields into columns; `csv-unalign-fields' undoes such alignment;
+;; separators can be hidden within aligned records.  `csv-transpose'
+;; interchanges rows and columns.  For details, see the documentation
+;; for the individual commands.
+
+;; CSV mode supports a generalised comma-separated values format
+;; (character-separated values) in which the fields can be separated
+;; by any of several single characters, specified by the value of the
+;; customizable user option `csv-separators'.  CSV data fields can be
+;; delimited by quote characters (and must if they contain separator
+;; characters).  This implementation supports quoted fields, where the
+;; quote characters allowed are specified by the value of the
+;; customizable user option `csv-field-quotes'.  By default, the only
+;; separator is a comma and the only field quote is a double quote.
+;; These user options can be changed ONLY by CUSTOMIZING them,
+;; e.g. via the command `customize-variable'.
+
+;; CSV mode commands ignore blank lines and comment lines beginning
+;; with the value of the buffer local variable `csv-comment-start',
+;; which by default is #.  The user interface is similar to that of
+;; the standard commands `sort-fields' and `sort-numeric-fields', but
+;; see the major mode documentation below.
+
+;; The global minor mode `csv-field-index-mode' provides display of
+;; the current field index in the mode line, cf. `line-number-mode'
+;; and `column-number-mode'.  It is on by default.
+
+;;; Installation:
+
+;; Put this file somewhere that Emacs can find it (i.e. in one of the
+;; directories in your `load-path' such as `site-lisp'), optionally
+;; byte-compile it (recommended), and put this in your .emacs file:
+;;
+;; (add-to-list 'auto-mode-alist '("\\.[Cc][Ss][Vv]\\'" . csv-mode))
+;; (autoload 'csv-mode "csv-mode"
+;;   "Major mode for editing comma-separated value files." t)
+
+;;; History:
+
+;; Begun on 15 November 2003 to provide lexicographic sorting of
+;; simple CSV data by field and released as csv.el.  Facilities to
+;; kill multiple fields and customize separator added on 9 April 2004.
+;; Converted to a major mode and renamed csv-mode.el on 10 April 2004,
+;; partly at the suggestion of Stefan Monnier <monnier at
+;; IRO.UMontreal.CA> to avoid conflict with csv.el by Ulf Jasper.
+;; Field alignment, comment support and CSV mode customization group
+;; added on 1 May 2004.  Support for index ranges added on 6 June
+;; 2004.  Multiple field separators added on 12 June 2004.
+;; Transposition added on 22 June 2004.  Separator invisibility added
+;; on 23 June 2004.
+
+;;; See also:
+
+;; the standard GNU Emacs 21 packages align.el, which will align
+;; columns within a region, and delim-col.el, which helps to prettify
+;; columns in a text region or rectangle;
+
+;; csv.el by Ulf Jasper <ulf.jasper at web.de>, which provides
+;; functions for reading/parsing comma-separated value files and is
+;; available at http://de.geocities.com/ulf_jasper/emacs.html (and in
+;; the gnu.emacs.sources archives).
+
+;;; To do (maybe):
+
+;; Make separators and quotes buffer-local and locally settable.
+;; Support (La)TeX tables: set separator and comment; support record
+;; end string.
+;; Convert comma-separated to space- or tab-separated.
+
+;;; Code:
+
+(defgroup CSV nil
+  "Major mode for editing files of comma-separated value type."
+  :group 'convenience)
+
+(defvar csv-separator-chars nil
+  "Field separators as a list of character.
+Set by customizing `csv-separators' -- do not set directly!")
+
+(defvar csv-separator-regexp nil
+  "Regexp to match a field separator.
+Set by customizing `csv-separators' -- do not set directly!")
+
+(defvar csv-skip-regexp nil
+  "Regexp used by `skip-chars-forward' etc. to skip fields.
+Set by customizing `csv-separators' -- do not set directly!")
+
+(defvar csv-font-lock-keywords nil
+  "Font lock keywords to highlight the field separators in CSV mode.
+Set by customizing `csv-separators' -- do not set directly!")
+
+(defcustom csv-separators '(",")
+  "Field separators: a list of *single-character* strings.
+For example: (\",\"), the default, or (\",\" \";\" \":\").
+Neighbouring fields may be separated by any one of these characters.
+The first is used when inserting a field separator into the buffer.
+All must be different from the field quote characters, `csv-field-quotes'."
+  ;; Suggested by Eckhard Neber <neber@mwt.e-technik.uni-ulm.de>
+  :group 'CSV
+  :type '(repeat string)
+  ;; Character would be better, but in Emacs 21.3 does not display
+  ;; correctly in a customization buffer.
+  :set (lambda (variable value)
+	 (mapc (lambda (x)
+		 (if (or (/= (length x) 1)
+			 (and (boundp 'csv-field-quotes)
+			      (member x csv-field-quotes)))
+		     (error)))
+	       value)
+	 (custom-set-default variable value)
+	 (setq csv-separator-chars (mapcar 'string-to-char value)
+	       csv-skip-regexp (apply 'concat "^\n" csv-separators)
+	       csv-separator-regexp (apply 'concat `("[" ,@value "]"))
+	       csv-font-lock-keywords
+	       ;; NB: csv-separator-face variable evaluates to itself.
+	       `((,csv-separator-regexp . csv-separator-face)))))
+
+(defcustom csv-field-quotes '("\"")
+  "Field quotes: a list of *single-character* strings.
+For example: (\"\\\"\"), the default, or (\"\\\"\" \"'\" \"`\").
+A field can be delimited by a pair of any of these characters.
+All must be different from the field separators, `csv-separators'."
+  :group 'CSV
+  :type '(repeat string)
+  ;; Character would be better, but in Emacs 21 does not display
+  ;; correctly in a customization buffer.
+  :set (lambda (variable value)
+	 (mapc (lambda (x)
+		 (if (or (/= (length x) 1)
+			 (member x csv-separators))
+		     (error)))
+	       value)
+	 (when (boundp 'csv-mode-syntax-table)
+	   ;; FIRST remove old quote syntax:
+	   (with-syntax-table text-mode-syntax-table
+	     (mapc (lambda (x)
+		     (modify-syntax-entry
+		      (string-to-char x)
+		      (string (char-syntax (string-to-char x)))
+		      ;; symbol-value to avoid compiler warning:
+		      (symbol-value 'csv-mode-syntax-table)))
+		   csv-field-quotes))
+	   ;; THEN set new quote syntax:
+	   (csv-set-quote-syntax value))
+	 ;; BEFORE setting new value of `csv-field-quotes':
+	 (custom-set-default variable value)))
+
+(defun csv-set-quote-syntax (field-quotes)
+  "Set syntax for field quote characters FIELD-QUOTES to be \"string\".
+FIELD-QUOTES should be a list of single-character strings."
+  (mapc (lambda (x)
+	  (modify-syntax-entry
+	   (string-to-char x) "\""
+	   ;; symbol-value to avoid compiler warning:
+	   (symbol-value 'csv-mode-syntax-table)))
+	field-quotes))
+
+(defvar csv-comment-start nil
+  "String that starts a comment line, or nil if no comment syntax.
+Such comment lines are ignored by CSV mode commands.
+This variable is buffer local\; its default value is that of
+`csv-comment-start-default'.  It is set by the function
+`csv-set-comment-start' -- do not set it directly!")
+
+(make-variable-buffer-local 'csv-comment-start)
+
+(defcustom csv-comment-start-default "#"
+  "String that starts a comment line, or nil if no comment syntax.
+Such comment lines are ignored by CSV mode commands.
+Default value of buffer-local variable `csv-comment-start'.
+Changing this variable does not affect any existing CSV mode buffer."
+  :group 'CSV
+  :type '(choice (const :tag "None" nil) string)
+  :set (lambda (variable value)
+	 (custom-set-default variable value)
+	 (set-default 'csv-comment-start value)))
+
+(defcustom csv-align-style 'left
+  "Aligned field style: one of 'left, 'centre, 'right or 'auto.
+Alignment style used by `csv-align-fields'.
+Auto-alignment means left align text and right align numbers."
+  :group 'CSV
+  :type '(choice (const left) (const centre)
+		 (const right) (const auto)))
+
+(defcustom csv-align-padding 1
+  "Aligned field spacing: must be a positive integer.
+Number of spaces used by `csv-align-fields' after separators."
+  :group 'CSV
+  :type 'integer)
+
+(defcustom csv-header-lines 0
+  "Header lines to skip when setting region automatically."
+  :group 'CSV
+  :type 'integer)
+
+(defcustom csv-invisibility-default nil
+  "If non-nil, make separators in aligned records invisible."
+  :group 'CSV
+  :type 'boolean)
+
+(defface csv-separator-face
+  '((((class color)) (:foreground "red"))
+    (t (:weight bold)))
+  "CSV mode face used to highlight separators."
+  :group 'CSV)
+
+;; This mechanism seems to keep XEmacs happy:
+(defvar csv-separator-face 'csv-separator-face
+  "Face name to use to highlight separators.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  Mode definition, key bindings and menu
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst csv-mode-line-help-echo
+  ;; See bindings.el for details of `mode-line-format' construction.
+  (get-text-property 0 'help-echo (car default-mode-line-format))
+  "Primary default mode line help echo text.")
+
+(defconst csv-mode-line-format
+  ;; See bindings.el for details of `mode-line-format' construction.
+  (append (butlast default-mode-line-format 2)
+	  (cons `(csv-field-index-string
+		  ("" csv-field-index-string
+		   ,(propertize "--" 'help-echo csv-mode-line-help-echo)))
+		(last default-mode-line-format 2)))
+  "Mode line format string for CSV mode.")
+
+(define-derived-mode csv-mode text-mode "CSV"
+  "Major mode for editing files of comma-separated value type.
+
+CSV mode is derived from `text-mode', and runs `text-mode-hook' before
+running `csv-mode-hook'.  It turns `auto-fill-mode' off by default.
+CSV mode can be customized by user options in the CSV customization
+group.  The separators are specified by the value of `csv-separators'.
+
+CSV mode commands ignore blank lines and comment lines beginning with
+the value of `csv-comment-start', which delimit \"paragraphs\".
+\"Sexp\" is re-interpreted to mean \"field\", so that `forward-sexp'
+\(\\[forward-sexp]), `kill-sexp' (\\[kill-sexp]), etc. all apply to fields.
+Standard comment commands apply, such as `comment-dwim' (\\[comment-dwim]).
+
+If `font-lock-mode' is enabled then separators, quoted values and
+comment lines are highlighted using respectively `csv-separator-face',
+`font-lock-string-face' and `font-lock-comment-face'.
+
+The user interface (UI) for CSV mode commands is similar to that of
+the standard commands `sort-fields' and `sort-numeric-fields', except
+that if there is no prefix argument then the UI prompts for the field
+index or indices.  In `transient-mark-mode' only: if the region is not
+set then the UI attempts to set it to include all consecutive CSV
+records around point, and prompts for confirmation; if there is no
+prefix argument then the UI prompts for it, offering as a default the
+index of the field containing point if the region was not set
+explicitly.  The region set automatically is delimited by blank lines
+and comment lines, and the number of header lines at the beginning of
+the region given by the value of `csv-header-lines' are skipped.
+
+Sort order is controlled by `csv-descending'.
+
+CSV mode provides the following specific keyboard key bindings:
+
+\\{csv-mode-map}"
+  (turn-off-auto-fill)
+  ;; Set syntax for field quotes:
+  (csv-set-quote-syntax csv-field-quotes)
+  ;; Make sexp functions apply to fields:
+  (set (make-local-variable 'forward-sexp-function) 'csv-forward-field)
+  ;; Paragraph means a group of contiguous records:
+  (make-local-variable 'paragraph-separate)
+  (make-local-variable 'paragraph-start)
+  ;; Comment support:
+  (make-local-variable 'comment-start)
+  (csv-set-comment-start csv-comment-start)
+  (setq
+   ;; Font locking -- separator plus syntactic:
+   font-lock-defaults '(csv-font-lock-keywords)
+   buffer-invisibility-spec csv-invisibility-default
+   ;; Mode line to support `csv-field-index-mode':
+   mode-line-format csv-mode-line-format)
+  ;; Enable or disable `csv-field-index-mode' (could probably do this
+  ;; a bit more efficiently):
+  (csv-field-index-mode (symbol-value 'csv-field-index-mode)))
+
+(defun csv-set-comment-start (string)
+  "Set comment start for this CSV mode buffer to STRING.
+It must be either a string or nil."
+  (interactive
+   (list (edit-and-eval-command
+	  "Comment start (string or nil): " csv-comment-start)))
+  (setq csv-comment-start string
+	paragraph-separate "[:space:]*$" ; white space
+	paragraph-start "\n")		; must include \n explicitly!
+  (if string
+      (progn
+	(setq paragraph-separate (concat paragraph-separate "\\|" string)
+	      paragraph-start (concat paragraph-start "\\|" string)
+	      comment-start string)
+	(modify-syntax-entry
+	 (string-to-char string) "<" csv-mode-syntax-table)
+	(modify-syntax-entry ?\n ">" csv-mode-syntax-table))
+    (with-syntax-table text-mode-syntax-table
+      (modify-syntax-entry (string-to-char string)
+			   (string (char-syntax (string-to-char string)))
+			   csv-mode-syntax-table)
+      (modify-syntax-entry ?\n
+			   (string (char-syntax ?\n))
+			   csv-mode-syntax-table))))
+
+(add-to-list 'auto-mode-alist '("\\.[Cc][Ss][Vv]\\'" . csv-mode))
+
+(define-key csv-mode-map [(control ?c) (control ?v)] 'csv-toggle-invisibility)
+(define-key csv-mode-map [(control ?c) (control ?t)] 'csv-transpose)
+(define-key csv-mode-map [(control ?c) (control ?c)] 'csv-set-comment-start)
+(define-key csv-mode-map [(control ?c) (control ?u)] 'csv-unalign-fields)
+(define-key csv-mode-map [(control ?c) (control ?a)] 'csv-align-fields)
+(define-key csv-mode-map [(control ?c) (control ?z)] 'csv-yank-as-new-table)
+(define-key csv-mode-map [(control ?c) (control ?y)] 'csv-yank-fields)
+(define-key csv-mode-map [(control ?c) (control ?k)] 'csv-kill-fields)
+(define-key csv-mode-map [(control ?c) (control ?d)] 'csv-toggle-descending)
+(define-key csv-mode-map [(control ?c) (control ?r)] 'csv-reverse-region)
+(define-key csv-mode-map [(control ?c) (control ?n)] 'csv-sort-numeric-fields)
+(define-key csv-mode-map [(control ?c) (control ?s)] 'csv-sort-fields)
+
+(defvar csv-descending nil
+  "If non-nil, CSV mode sort functions sort in order of descending sort key.
+Usually they sort in order of ascending sort key.")
+
+(defun csv-toggle-descending ()
+  "Toggle `csv-descending'."
+  (interactive)
+  (setq csv-descending (not csv-descending))
+  (message "Sort order is %sscending" (if csv-descending "de" "a")))
+
+(defun csv-toggle-invisibility ()
+  "Toggle `buffer-invisibility-spec'."
+  (interactive)
+  (setq buffer-invisibility-spec (not buffer-invisibility-spec))
+  (message "Separators in aligned records will be %svisible \
+\(after re-aligning if soft\)"
+	   (if buffer-invisibility-spec "in" ""))
+  (redraw-frame (selected-frame)))
+
+(easy-menu-define
+  csv-menu
+  csv-mode-map
+  "CSV major mode menu keymap"
+  '("CSV"
+    ["Sort By Field Lexicographically" csv-sort-fields :active t
+     :help "Sort lines in region lexicographically by the specified field"]
+    ["Sort By Field Numerically" csv-sort-numeric-fields :active t
+     :help "Sort lines in region numerically by the specified field"]
+    ["Reverse Order of Lines" csv-reverse-region :active t
+     :help "Reverse the order of the lines in the region"]
+    ["Use Descending Sort Order" csv-toggle-descending :active t
+     :style toggle :selected csv-descending
+     :help "If selected, use descending order when sorting"]
+    "--"
+    ["Kill Fields (Columns)" csv-kill-fields :active t
+     :help "Kill specified fields of each line in the region"]
+    ["Yank Fields (Columns)" csv-yank-fields :active t
+     :help "Yank killed fields as specified field of each line in region"]
+    ["Yank As New Table" csv-yank-as-new-table :active t
+     :help "Yank killed fields as a new table at point"]
+    ["Align Fields into Columns" csv-align-fields :active t
+     :help "Align the start of every field of each line in the region"]
+    ["Unalign Columns into Fields" csv-unalign-fields :active t
+     :help "Undo soft alignment and optionally remove redundant white space"]
+    ["Transpose Rows and Columns" csv-transpose :active t
+     :help "Rewrite rows (which may have different lengths) as columns"]
+    "--"
+    ["Forward Field" forward-sexp :active t
+     :help "Move forward across one field\; with ARG, do it that many times"]
+    ["Backward Field" backward-sexp :active t
+     :help "Move backward across one field\; with ARG, do it that many times"]
+    ["Kill Field Forward" kill-sexp :active t
+     :help "Kill field following cursor\; with ARG, do it that many times"]
+    ["Kill Field Backward" backward-kill-sexp :active t
+     :help "Kill field preceding cursor\; with ARG, do it that many times"]
+    "--"
+    ("Alignment Style"
+     ["Left" (setq csv-align-style 'left) :active t
+      :style radio :selected (eq csv-align-style 'left)
+      :help "If selected, `csv-align-fields' left aligns fields"]
+     ["Centre" (setq csv-align-style 'centre) :active t
+      :style radio :selected (eq csv-align-style 'centre)
+      :help "If selected, `csv-align-fields' centres fields"]
+     ["Right" (setq csv-align-style 'right) :active t
+      :style radio :selected (eq csv-align-style 'right)
+      :help "If selected, `csv-align-fields' right aligns fields"]
+     ["Auto" (setq csv-align-style 'auto) :active t
+      :style radio :selected (eq csv-align-style 'auto)
+      :help "\
+If selected, `csv-align-fields' left aligns text and right aligns numbers"]
+     )
+    ["Show Current Field Index" csv-field-index-mode :active t
+     :style toggle :selected csv-field-index-mode
+     :help "If selected, display current field index in mode line"]
+    ["Make Separators Invisible" csv-toggle-invisibility :active t
+     :style toggle :selected buffer-invisibility-spec
+     :help "If selected, separators in aligned records are invisible"]
+    ["Set Buffer's Comment Start" csv-set-comment-start :active t
+     :help "Set comment start string for this buffer"]
+    ["Customize CSV Mode" (customize-group 'CSV) :active t
+     :help "Open a customization buffer to change CSV mode options"]
+    ))
+
+(require 'sort)
+
+(defsubst csv-not-looking-at-record ()
+  "Return t if looking at blank or comment line, nil otherwise.
+Assumes point is at beginning of line."
+  (looking-at paragraph-separate))
+
+(defun csv-interactive-args (&optional type)
+  "Get arg or field(s) and region interactively, offering sensible defaults.
+Signal an error if the buffer is read-only.
+If TYPE is noarg then return a list `(beg end)'.
+Otherwise, return a list `(arg beg end)', where arg is:
+  the raw prefix argument by default\;
+  a single field index if TYPE is single\;
+  a list of field indices or index ranges if TYPE is multiple.
+Field defaults to the current prefix arg\; if not set, prompt user.
+
+A field index list consists of positive or negative integers or ranges,
+separated by any non-integer characters.  A range has the form m-n,
+where m and n are positive or negative integers, m < n, and n defaults
+to the last field index if omitted.
+
+In transient mark mode, if the mark is not active then automatically
+select and highlight CSV records around point, and query user.
+The default field when read interactively is the current field."
+  ;; Must be run interactively to activate mark!
+  (let* ((arg current-prefix-arg) (default-field 1)
+	 (region
+	  (if (and transient-mark-mode (not mark-active))
+	      ;; Set region automatically:
+	      (save-excursion
+		(let (startline lbp)
+		  (if arg
+		      (beginning-of-line)
+		    (setq lbp (line-beginning-position))
+		    (while (re-search-backward csv-separator-regexp lbp 1)
+		      ;; Move as far as possible, i.e. to beginning of line.
+		      (setq default-field (1+ default-field))))
+		  (if (csv-not-looking-at-record)
+		      (error "Point may not be within CSV records"))
+		  (setq startline (point))
+		  ;; Set mark at beginning of region:
+		  (while (not (or (bobp) (csv-not-looking-at-record)))
+		    (forward-line -1))
+		  (if (csv-not-looking-at-record) (forward-line 1))
+		  ;; Skip header lines:
+		  (forward-line csv-header-lines)
+		  (set-mark (point))	; OK since in save-excursion
+		  ;; Move point to end of region:
+		  (goto-char startline)
+		  (beginning-of-line)
+		  (while (not (or (eobp) (csv-not-looking-at-record)))
+		    (forward-line 1))
+		  ;; Show mark briefly if necessary:
+		  (unless (and (pos-visible-in-window-p)
+			       (pos-visible-in-window-p (mark)))
+		    (exchange-point-and-mark)
+		    (sit-for 1)
+		    (exchange-point-and-mark))
+		  (or (y-or-n-p "Region OK? ")
+		      (error "Action aborted by user"))
+		  (message nil)		; clear y-or-n-p message
+		  (list (region-beginning) (region-end))))
+	    ;; Use region set by user:
+	    (list (region-beginning) (region-end)))))
+    (setq default-field (number-to-string default-field))
+    (cond
+     ((eq type 'multiple)
+      (if arg
+	  ;; Ensure that field is a list:
+	  (or (consp arg)
+	      (setq arg (list (prefix-numeric-value arg))))
+	;; Read field interactively, ignoring non-integers:
+	(setq arg
+	      (mapcar
+	       (lambda (x)
+		 (if (string-match "-" x 1) ; not first character
+		     ;; Return a range as a pair - the cdr may be nil:
+		     (let ((m (substring x 0 (match-beginning 0)))
+			   (n (substring x (match-end 0))))
+		       (cons (car (read-from-string m))
+			     (and (not (string= n ""))
+				  (car (read-from-string n)))))
+		   ;; Return a number as a number:
+		   (car (read-from-string x))))
+	       (split-string
+		(read-string
+		 "Fields (sequence of integers or ranges): " default-field)
+		"[^-+0-9]+")))))
+     ((eq type 'single)
+      (if arg
+	  (setq arg (prefix-numeric-value arg))
+	(while (not (integerp arg))
+	  (setq arg (eval-minibuffer "Field (integer): " default-field))))))
+    (if (eq type 'noarg) region (cons arg region))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  Sorting by field
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun csv-nextrecfun ()
+  "Called by `csv-sort-fields-1' with point at end of previous record.
+It moves point to the start of the next record.
+It should move point to the end of the buffer if there are no more records."
+  (forward-line)
+  (while (and (not (eobp)) (csv-not-looking-at-record))
+    (forward-line)))
+
+(defun csv-sort-fields-1 (field beg end startkeyfun endkeyfun)
+  "Modified version of `sort-fields-1' that skips blank or comment lines.
+
+FIELD is a single field index, and BEG and END specify the region to
+sort.
+
+STARTKEYFUN moves from the start of the record to the start of the key.
+It may return either a non-nil value to be used as the key, or
+else the key is the substring between the values of point after
+STARTKEYFUN and ENDKEYFUN are called.  If STARTKEYFUN is nil, the key
+starts at the beginning of the record.
+
+ENDKEYFUN moves from the start of the sort key to the end of the sort key.
+ENDKEYFUN may be nil if STARTKEYFUN returns a value or if it would be the
+same as ENDRECFUN."
+  (let ((tbl (syntax-table)))
+    (if (zerop field) (setq field 1))
+    (unwind-protect
+	(save-excursion
+	  (save-restriction
+	    (narrow-to-region beg end)
+	    (goto-char (point-min))
+	    (set-syntax-table sort-fields-syntax-table)
+	    (sort-subr csv-descending
+		       'csv-nextrecfun 'end-of-line
+		       startkeyfun endkeyfun)))
+      (set-syntax-table tbl))))
+
+(defun csv-sort-fields (field beg end)
+  "Sort lines in region lexicographically by the ARGth field of each line.
+If not set, the region defaults to the CSV records around point.
+Fields are separated by `csv-separators' and null fields are allowed anywhere.
+Field indices increase from 1 on the left or decrease from -1 on the right.
+A prefix argument specifies a single field, otherwise prompt for field index.
+Ignore blank and comment lines.  The variable `sort-fold-case'
+determines whether alphabetic case affects the sort order.
+When called non-interactively, FIELD is a single field index\;
+BEG and END specify the region to sort."
+  ;; (interactive "*P\nr")
+  (interactive (csv-interactive-args 'single))
+  (barf-if-buffer-read-only)
+  (csv-sort-fields-1 field beg end
+		     (lambda () (csv-sort-skip-fields field) nil)
+		     (lambda () (skip-chars-forward csv-skip-regexp))))
+
+(defun csv-sort-numeric-fields (field beg end)
+  "Sort lines in region numerically by the ARGth field of each line.
+If not set, the region defaults to the CSV records around point.
+Fields are separated by `csv-separators'.
+Null fields are allowed anywhere and sort as zeros.
+Field indices increase from 1 on the left or decrease from -1 on the right.
+A prefix argument specifies a single field, otherwise prompt for field index.
+Specified non-null field must contain a number in each line of the region,
+which may begin with \"0x\" or \"0\" for hexadecimal and octal values.
+Otherwise, the number is interpreted according to sort-numeric-base.
+Ignore blank and comment lines.
+When called non-interactively, FIELD is a single field index\;
+BEG and END specify the region to sort."
+  ;; (interactive "*P\nr")
+  (interactive (csv-interactive-args 'single))
+  (barf-if-buffer-read-only)
+  (csv-sort-fields-1 field beg end
+		 (lambda ()
+		   (csv-sort-skip-fields field)
+		   (let* ((case-fold-search t)
+			  (base
+			   (if (looking-at "\\(0x\\)[0-9a-f]\\|\\(0\\)[0-7]")
+			       (cond ((match-beginning 1)
+				      (goto-char (match-end 1))
+				      16)
+				     ((match-beginning 2)
+				      (goto-char (match-end 2))
+				      8)
+				     (t nil)))))
+		     (string-to-number (buffer-substring (point)
+							 (save-excursion
+							   (forward-sexp 1)
+							   (point)))
+				       (or base sort-numeric-base))))
+		 nil))
+
+(defun csv-reverse-region (beg end)
+  "Reverse the order of the lines in the region.
+This is just a CSV-mode style interface to `reverse-region', which is
+the function that should be used non-interactively.  It takes two
+point or marker arguments, BEG and END, delimiting the region."
+  ;; (interactive "*P\nr")
+  (interactive (csv-interactive-args 'noarg))
+  (barf-if-buffer-read-only)
+  (reverse-region beg end))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  Moving by field
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defsubst csv-end-of-field ()
+  "Skip forward over one field."
+  (skip-syntax-forward " ")
+  (if (eq (char-syntax (following-char)) ?\")
+      (goto-char (scan-sexps (point) 1)))
+  (skip-chars-forward csv-skip-regexp))
+
+(defsubst csv-beginning-of-field ()
+  "Skip backward over one field."
+  (skip-syntax-backward " ")
+  (if (eq (char-syntax (preceding-char)) ?\")
+      (goto-char (scan-sexps (point) -1)))
+  (skip-chars-backward csv-skip-regexp))
+
+(defun csv-forward-field (arg)
+  "Move forward across one field, cf. `forward-sexp'.
+With ARG, do it that many times.  Negative arg -N means
+move backward across N fields."
+  (interactive "p")
+  (if (< arg 0)
+      (csv-backward-field (- arg))
+    (while (>= (setq arg (1- arg)) 0)
+      (if (or (bolp)
+	      (when (and (not (eobp)) (eolp)) (forward-char) t))
+	  (while (and (not (eobp)) (csv-not-looking-at-record))
+	    (forward-line 1)))
+      (if (memq (following-char) csv-separator-chars) (forward-char))
+      (csv-end-of-field))))
+
+(defun csv-backward-field (arg)
+  "Move backward across one field, cf. `backward-sexp'.
+With ARG, do it that many times.  Negative arg -N means
+move forward across N fields."
+  (interactive "p")
+  (if (< arg 0)
+      (csv-forward-field (- arg))
+    (while (>= (setq arg (1- arg)) 0)
+      (when (or (eolp)
+		(when (and (not (bobp)) (bolp)) (backward-char) t))
+	(while (progn
+		 (beginning-of-line)
+		 (csv-not-looking-at-record))
+	  (backward-char))
+	(end-of-line))
+      (if (memq (preceding-char) csv-separator-chars) (backward-char))
+      (csv-beginning-of-field))))
+
+(defun csv-sort-skip-fields (n &optional yank)
+  "Position point at the beginning of field N on the current line.
+Fields are separated by `csv-separators'\; null terminal field allowed.
+Assumes point is initially at the beginning of the line.
+YANK non-nil allows N to be greater than the number of fields, in
+which case extend the record as necessary."
+  (if (> n 0)
+      ;; Skip across N - 1 fields.
+      (let ((i (1- n)))
+	(while (> i 0)
+	  (csv-end-of-field)
+	  (if (eolp)
+	      (if yank
+		  (if (> i 1) (insert (car csv-separators)))
+		(error "Line has too few fields: %s"
+		       (buffer-substring
+			(save-excursion (beginning-of-line) (point))
+			(save-excursion (end-of-line) (point)))))
+	    (forward-char))		; skip separator
+	  (setq i (1- i))))
+    (end-of-line)
+    ;; Skip back across -N - 1 fields.
+    (let ((i (1- (- n))))
+      (while (> i 0)
+	(csv-beginning-of-field)
+	(if (bolp)
+	    (error "Line has too few fields: %s"
+		   (buffer-substring
+		    (save-excursion (beginning-of-line) (point))
+		    (save-excursion (end-of-line) (point)))))
+	(backward-char)			; skip separator
+	(setq i (1- i)))
+      ;; Position at the front of the field
+      ;; even if moving backwards.
+      (csv-beginning-of-field))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  Field index mode
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Based partly on paren.el
+
+(defcustom csv-field-index-delay 0.125
+  "Time in seconds to delay before updating field index display."
+  :group 'CSV
+  :type '(number :tag "seconds"))
+
+(defvar csv-field-index-idle-timer nil)
+
+(defvar csv-field-index-string nil)
+(make-variable-buffer-local 'csv-field-index-string)
+
+(defvar csv-field-index-old nil)
+(make-variable-buffer-local 'csv-field-index-old)
+
+(define-minor-mode csv-field-index-mode
+  "Toggle CSV-Field-Index mode.
+With prefix ARG, turn CSV-Field-Index mode on if and only if ARG is positive.
+Returns the new status of CSV-Field-Index mode (non-nil means on).
+When CSV-Field-Index mode is enabled, the current field index appears in
+the mode line after `csv-field-index-delay' seconds of Emacs idle time."
+  :group 'CSV
+  :global t
+  :init-value t		       ; for documentation, since default is t
+  ;; This macro generates a function that first sets the mode
+  ;; variable, then runs the following code, runs the mode hooks,
+  ;; displays a message if interactive, updates the mode line and
+  ;; finally returns the variable value.
+
+  ;; First, always disable the mechanism (to avoid having two timers):
+  (when csv-field-index-idle-timer
+    (cancel-timer csv-field-index-idle-timer)
+    (setq csv-field-index-idle-timer nil))
+  ;; Now, if the mode is on and any buffer is in CSV mode then
+  ;; re-initialize and enable the mechanism by setting up a new timer:
+  (if csv-field-index-mode
+      (if (memq t (mapcar (lambda (buffer)
+			    (with-current-buffer buffer
+			      (when (eq major-mode 'csv-mode)
+				(setq csv-field-index-string nil
+				      csv-field-index-old nil)
+				t)))
+			  (buffer-list)))
+	  (setq csv-field-index-idle-timer
+		(run-with-idle-timer csv-field-index-delay t
+				     'csv-field-index)))
+    ;; but if the mode is off then remove the display from the mode
+    ;; lines of all CSV buffers:
+    (mapc (lambda (buffer)
+	    (with-current-buffer buffer
+	      (when (eq major-mode 'csv-mode)
+		(setq csv-field-index-string nil
+		      csv-field-index-old nil)
+		(force-mode-line-update))))
+	    (buffer-list))))
+
+(defun csv-field-index ()
+  "Construct `csv-field-index-string' to display in mode line.
+Called by `csv-field-index-idle-timer'."
+  (if (eq major-mode 'csv-mode)
+      (save-excursion
+	(let ((lbp (line-beginning-position)) (field 1))
+	  (while (re-search-backward csv-separator-regexp lbp 1)
+	    ;; Move as far as possible, i.e. to beginning of line.
+	    (setq field (1+ field)))
+	  (if (csv-not-looking-at-record) (setq field nil))
+	  (when (not (eq field csv-field-index-old))
+	    (setq csv-field-index-old field
+		  csv-field-index-string
+		  (and field (propertize (format "F%d" field)
+					 'help-echo csv-mode-line-help-echo)))
+	    (force-mode-line-update))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  Killing and yanking fields
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar csv-killed-fields nil
+  "A list of the fields or sub-records last killed by `csv-kill-fields'.")
+
+(defun csv-kill-fields (fields beg end)
+  "Kill specified fields of each line in the region.
+If not set, the region defaults to the CSV records around point.
+Fields are separated by `csv-separators' and null fields are allowed anywhere.
+Field indices increase from 1 on the left or decrease from -1 on the right.
+The fields are stored for use by `csv-yank-fields'.  Fields can be
+specified in any order but are saved in increasing index order.
+Ignore blank and comment lines.
+
+When called interactively, a prefix argument specifies a single field,
+otherwise prompt for a field list, which may include ranges in the form
+m-n, where m < n and n defaults to the last field index if omitted.
+
+When called non-interactively, FIELDS is a single field index or a
+list of field indices, with ranges specified as (m.n) or (m), and BEG
+and END specify the region to process."
+  ;; (interactive "*P\nr")
+  (interactive (csv-interactive-args 'multiple))
+  (barf-if-buffer-read-only)
+  ;; Kill the field(s):
+  (setq csv-killed-fields nil)
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (goto-char (point-min))
+      (if (or (cdr fields) (consp (car fields)))
+	  (csv-kill-many-columns fields)
+	(csv-kill-one-column (car fields)))))
+  (setq csv-killed-fields (nreverse csv-killed-fields)))
+
+(defmacro csv-kill-one-field (field killed-fields)
+  "Kill field with index FIELD in current line.
+Save killed field by `push'ing onto KILLED-FIELDS.
+Assumes point is at beginning of line.
+Called by `csv-kill-one-column' and `csv-kill-many-columns'."
+  `(progn
+     ;; Move to start of field to kill:
+     (csv-sort-skip-fields ,field)
+     ;; Kill to end of field (cf. `kill-region'):
+     (push (delete-and-extract-region
+	    (point)
+	    (progn (csv-end-of-field) (point)))
+	   ,killed-fields)
+     (if (eolp) (delete-char -1)    ; delete trailing separator at eol
+       (delete-char 1))))	    ; or following separator otherwise
+
+(defun csv-kill-one-column (field)
+  "Kill field with index FIELD in all lines in (narrowed) buffer.
+Save killed fields in `csv-killed-fields'.
+Assumes point is at `point-min'.  Called by `csv-kill-fields'.
+Ignore blank and comment lines."
+  (while (not (eobp))
+    (or (csv-not-looking-at-record)
+	(csv-kill-one-field field csv-killed-fields))
+    (forward-line)))
+
+(defun csv-kill-many-columns (fields)
+  "Kill several fields in all lines in (narrowed) buffer.
+FIELDS is an unordered list of field indices.
+Save killed fields in increasing index order in `csv-killed-fields'.
+Assumes point is at `point-min'.  Called by `csv-kill-fields'.
+Ignore blank and comment lines."
+  (if (eolp) (error "First record is empty"))
+  ;; Convert non-positive to positive field numbers:
+  (let ((last 1) (f fields))
+    (csv-end-of-field)
+    (while (not (eolp))
+      (forward-char)			; skip separator
+      (csv-end-of-field)
+      (setq last (1+ last)))	     ; last = # fields in first record
+    (while f
+      (cond ((consp (car f))
+	     ;; Expand a field range: (m.n) -> m m+1 ... n-1 n.
+	     ;; If n is nil then it defaults to the number of fields.
+	     (let* ((range (car f)) (cdrf (cdr f))
+		    (m (car range)) (n (cdr range)))
+	       (if (< m 0) (setq m (+ m last 1)))
+	       (if n
+		   (if (< n 0) (setq n (+ n last 1)))
+		 (setq n last))
+	       (setq range (list n))
+	       (while (> n m) (push (setq n (1- n)) range))
+	       (setcar f (car range))
+	       (setcdr f (cdr range))
+	       (setcdr (setq f (last range)) cdrf)))
+	    ((zerop (car f)) (setcar f 1))
+	    ((< (car f) 0) (setcar f (+ f last 1))))
+      (setq f (cdr f))))
+  (goto-char (point-min))
+  ;; Kill from right to avoid miscounting:
+  (setq fields (sort fields '>))
+  (while (not (eobp))
+    (or (csv-not-looking-at-record)
+	(let ((fields fields) killed-fields field)
+	  (while fields
+	    (setq field (car fields)
+		  fields (cdr fields))
+	    (beginning-of-line)
+	    (csv-kill-one-field field killed-fields))
+	  (push (mapconcat 'identity killed-fields (car csv-separators))
+		csv-killed-fields)))
+    (forward-line)))
+
+(defun csv-yank-fields (field beg end)
+  "Yank fields as the ARGth field of each line in the region.
+ARG may be arbitrarily large and records are extended as necessary.
+If not set, the region defaults to the CSV records around point\;
+if point is not in a CSV record then offer to yank as a new table.
+The fields yanked are those last killed by `csv-kill-fields'.
+Fields are separated by `csv-separators' and null fields are allowed anywhere.
+Field indices increase from 1 on the left or decrease from -1 on the right.
+A prefix argument specifies a single field, otherwise prompt for field index.
+Ignore blank and comment lines.  When called non-interactively, FIELD
+is a single field index\; BEG and END specify the region to process."
+  ;; (interactive "*P\nr")
+  (interactive (condition-case err
+		   (csv-interactive-args 'single)
+		 (error (list nil nil err))))
+  (barf-if-buffer-read-only)
+  (if (null beg)
+      (if (y-or-n-p (concat (error-message-string end)
+			    ".  Yank as a new table? "))
+	  (csv-yank-as-new-table)
+	(error (error-message-string end)))
+    (if (<= field 0) (setq field (1+ field)))
+    (save-excursion
+      (save-restriction
+	(narrow-to-region beg end)
+	(goto-char (point-min))
+	(let ((fields csv-killed-fields))
+	  (while (not (eobp))
+	    (unless (csv-not-looking-at-record)
+	      ;; Yank at start of specified field if possible,
+	      ;; otherwise yank at end of record:
+	      (if (zerop field)
+		  (end-of-line)
+		(csv-sort-skip-fields field 'yank))
+	      (and (eolp) (insert (car csv-separators)))
+	      (when fields
+		(insert (car fields))
+		(setq fields (cdr fields)))
+	      (or (eolp) (insert (car csv-separators))))
+	    (forward-line)))))))
+
+(defun csv-yank-as-new-table ()
+  "Yank fields as a new table starting at point.
+The fields yanked are those last killed by `csv-kill-fields'."
+  (interactive "*")
+  (let ((fields csv-killed-fields))
+    (while fields
+      (insert (car fields) ?\n)
+      (setq fields (cdr fields)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  Aligning fields
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun csv-align-fields (hard beg end)
+  "Align all the fields in the region to form columns.
+The alignment style is specified by `csv-align-style'.  The number of
+spaces specified by `csv-align-fields' appears after each separator.
+Use soft alignment done by displaying virtual white space after the
+separators unless invoked with an argument, in which case insert real
+space characters into the buffer after the separators.
+Unalign first (see `csv-unalign-fields').  Ignore blank and comment lines.
+
+In hard-aligned records, separators become invisible whenever
+`buffer-invisibility-spec' is non-nil.  In soft-aligned records, make
+separators invisible if and only if `buffer-invisibility-spec' is
+non-nil when the records are aligned\; this can be changed only by
+re-aligning.  \(Unaligning always makes separators visible.)
+
+When called non-interactively, use hard alignment if HARD is non-nil\;
+BEG and END specify the region to align."
+  (interactive (csv-interactive-args))
+  (setq end (set-marker (make-marker) end))
+  (csv-unalign-fields hard beg end) ; if hard then barfs if buffer read only
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (set-marker end nil)
+      (goto-char (point-min))
+      (let (widths)
+	;; Construct list of column widths:
+	(while (not (eobp))		; for each record...
+	  (or (csv-not-looking-at-record)
+	      (let ((w widths) x)
+		(setq beg (point))	; beginning of current field
+		(while (not (eolp))
+		  (csv-end-of-field)
+		  (setq x (- (point) beg)) ; field width
+		  (if w
+		      (if (> x (car w)) (setcar w x))
+		    (setq w (list x)
+			  widths (nconc widths w)))
+		  (or (eolp) (forward-char)) ; skip separator
+		  (setq w (cdr w)
+			beg (point)))))
+	  (forward-line))
+
+	;; Align fields:
+	(goto-char (point-min))
+	(while (not (eobp))		; for each record...
+	  (or (csv-not-looking-at-record)
+	      (let ((w widths) (padding 0) x)
+		(setq beg (point))	; beginning of current field
+		(while (and w (not (eolp)))
+		  (let ((left-padding 0) (right-padding 0) overlay)
+		    (csv-end-of-field)
+		    (set-marker end (point)) ; end of current field
+		    (setq x (- (point) beg) ; field width
+			  x (- (car w) x)) ; required padding
+
+		    ;; beg = beginning of current field
+		    ;; end = (point) = end of current field
+
+		    ;; Compute required padding:
+		    (cond
+		     ((eq csv-align-style 'left)
+		      ;; Left align -- pad on the right:
+		      (setq left-padding csv-align-padding
+			    right-padding x))
+		     ((eq csv-align-style 'right)
+		      ;; Right align -- pad on the left:
+		      (setq left-padding (+ csv-align-padding x)))
+		     ((eq csv-align-style 'auto)
+		      ;; Auto align -- left align text, right align numbers:
+		      (if (string-match "\\`[-+.[:digit:]]+\\'"
+					(buffer-substring beg (point)))
+			  ;; Right align -- pad on the left:
+			  (setq left-padding (+ csv-align-padding x))
+			;; Left align -- pad on the right:
+			(setq left-padding csv-align-padding
+			      right-padding x)))
+		     ((eq csv-align-style 'centre)
+		      ;; Centre -- pad on both left and right:
+		      (let ((y (/ x 2))) ; truncated integer quotient
+			(setq left-padding (+ csv-align-padding y)
+			      right-padding (- x y)))))
+
+		    (if hard
+			;; Hard alignment...
+			(progn
+			  (when (> left-padding 0) ; pad on the left
+			    ;; Insert spaces before field:
+			    (if (= beg end) ; null field
+				(insert (make-string left-padding ?\ ))
+			      (goto-char beg) ; beginning of current field
+			      (insert (make-string left-padding ?\ ))
+			      (goto-char end))) ; end of current field
+			  (unless (eolp)
+			    (if (> right-padding 0) ; pad on the right
+				;; Insert spaces after field:
+				(insert (make-string right-padding ?\ )))
+			    ;; Make separator (potentially) invisible;
+			    ;; in Emacs 21.3, neighbouring overlays
+			    ;; conflict, so use the following only
+			    ;; with hard alignment:
+			    (overlay-put (make-overlay (point) (1+ (point)))
+					 ;; 'face 'secondary-selection) ; test
+					 'invisible t)
+			    (forward-char))) ; skip separator
+
+		      ;; Soft alignment...
+
+		      (if buffer-invisibility-spec ; csv-hide-separators
+
+			  ;; Hide separators...
+			  (progn
+			    ;; Merge right-padding from previous field
+			    ;; with left-padding from this field:
+			    (setq padding (+ padding left-padding))
+			    (when (> padding 0)
+			      (goto-char beg) ; beginning of current field
+			      (if (bolp)
+				  ;; Display spaces before first field
+				  ;; by overlaying first character:
+				  (overlay-put
+				   (make-overlay (point) (1+ (point)))
+				   'before-string
+				   (make-string padding ?\ ))
+				;; Display separator as spaces:
+				(overlay-put
+				   (make-overlay (1- (point)) (point))
+				   ;; 'face 'secondary-selection)) ; test
+				   ;; 'display (make-string padding ?\ )))
+				   ;; Above 'display mangles buffer
+				   ;; horribly if any string is empty!
+				   'display `(space :width ,padding)))
+			      (goto-char end)) ; end of current field
+			    (unless (eolp)
+			      (setq padding right-padding)
+			      (forward-char))) ; skip separator
+
+			;; Do not hide separators...
+			(when (> left-padding 0) ; pad on the left
+			  ;; Display spaces before field:
+			  (setq overlay (make-overlay beg (point)))
+			  (overlay-put overlay 'before-string
+				       (make-string left-padding ?\ )))
+			(unless (eolp)
+			  (if (> right-padding 0) ; pad on the right
+			      ;; Display spaces after field:
+			      (overlay-put
+			       (or overlay
+				   (make-overlay beg (point)))
+			       'after-string (make-string right-padding ?\ )))
+			  (forward-char))) ; skip separator
+
+		      ))
+
+		  (setq w (cdr w)
+			beg (point)))))
+	  (forward-line)))))
+  (set-marker end nil))
+
+(defun csv-unalign-fields (hard beg end)
+  "Undo soft alignment and optionally remove redundant white space.
+Undo soft alignment introduced by `csv-align-fields'.  If invoked with
+an argument then also remove all spaces and tabs around separators.
+Also make all invisible separators visible again.
+Ignore blank and comment lines.  When called non-interactively, remove
+spaces and tabs if HARD non-nil\; BEG and END specify region to unalign."
+  (interactive (csv-interactive-args))
+  ;; Remove any soft alignment:
+  (mapc 'delete-overlay	(overlays-in beg end))
+  (when hard
+    (barf-if-buffer-read-only)
+    ;; Remove any white-space padding around separators:
+    (save-excursion
+      (save-restriction
+	(narrow-to-region beg end)
+	(goto-char (point-min))
+	(while (not (eobp))
+	  (or (csv-not-looking-at-record)
+	      (while (not (eolp))
+		;; Delete horizontal white space forward:
+		;; (delete-horizontal-space)
+		;; This relies on left-to-right argument evaluation;
+		;; see info node (elisp) Function Forms.
+		(delete-region (point)
+			       (+ (point) (skip-chars-forward " \t")))
+		(csv-end-of-field)
+		;; Delete horizontal white space backward:
+		;; (delete-horizontal-space t)
+		(delete-region (point)
+			       (+ (point) (skip-chars-backward " \t")))
+		(or (eolp) (forward-char))))
+	  (forward-line))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  Transposing rows and columns
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun csv-transpose (beg end)
+  "Rewrite rows (which may have different lengths) as columns.
+Null fields are introduced as necessary within records but are
+stripped from the ends of records.  Preserve soft alignment.
+This function is its own inverse.  Ignore blank and comment lines.
+When called non-interactively, BEG and END specify region to process."
+  ;; (interactive "*P\nr")
+  (interactive (csv-interactive-args 'noarg))
+  (barf-if-buffer-read-only)
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (goto-char (point-min))
+      ;; Delete rows and collect them as a reversed list of lists of
+      ;; fields, skipping comment and blank lines:
+      (let ((sep (car csv-separators))
+	    (align (overlays-in beg end))
+	    rows columns)
+	;; Remove soft alignment if necessary:
+	(when align
+	  (mapc 'delete-overlay	align)
+	  (setq align t))
+	(while (not (eobp))
+	  (if (csv-not-looking-at-record)
+	      ;; Skip blank and comment lines:
+	      (forward-line)
+	    (let ((lep (line-end-position)))
+	      (push
+	       (csv-split-string
+		(buffer-substring-no-properties (point) lep)
+		csv-separator-regexp nil t)
+	       rows)
+	      (delete-region (point) lep)
+	      (or (eobp) (delete-char 1)))))
+	;; Rows must have monotonic decreasing lengths to be
+	;; transposable, so ensure this by padding with null fields.
+	;; rows is currently a reversed list of field lists, which
+	;; must therefore have monotonic increasing lengths.
+	(let ((oldlen (length (car rows))) newlen
+	      (r (cdr rows)))
+	  (while r
+	    (setq newlen (length (car r)))
+	    (if (< newlen oldlen)
+		(nconc (car r) (make-list (- oldlen newlen) nil))
+	      (setq oldlen newlen))
+	    (setq r (cdr r))))
+	;; Collect columns as a reversed list of lists of fields:
+	(while rows
+	  (let (column (r rows) row)
+	    (while r
+	      (setq row (car r))
+	      ;; Provided it would not be a trailing null field, push
+	      ;; field onto column:
+	      (if (or column (string< "" (car row)))
+		  (push (car row) column))
+	      ;; Pop field off row:
+	      (setcar r (cdr row))
+	      ;; If row is now empty then remove it:
+	      (or (car r) (setq rows (cdr rows)))
+	      (setq r (cdr r)))
+	    (push column columns)))
+	;; Insert columns into buffer as rows:
+	(setq columns (nreverse columns))
+	(while columns
+	  (insert (mapconcat 'identity (car columns) sep) ?\n)
+	  (setq columns (cdr columns)))
+	;; Re-do soft alignment if necessary:
+	(if align (csv-align-fields nil (point-min) (point-max)))))))
+
+;; The following generalised version of `split-string' is taken from
+;; the development version of WoMan and should probably replace the
+;; standard version in subr.el.  However, CSV mode (currently) needs
+;; only the `allowbeg' option.
+
+(defun csv-split-string
+  (string &optional separators subexp allowbeg allowend)
+  "Splits STRING into substrings where there are matches for SEPARATORS.
+Each match for SEPARATORS is a splitting point.
+The substrings between the splitting points are made into a list
+which is returned.
+If SEPARATORS is absent, it defaults to \"[ \\f\\t\\n\\r\\v]+\".
+SUBEXP specifies a subexpression of SEPARATORS to be the splitting
+point\; it defaults to 0.
+
+If there is a match for SEPARATORS at the beginning of STRING, we do
+not include a null substring for that, unless ALLOWBEG is non-nil.
+Likewise, if there is a match at the end of STRING, we do not include
+a null substring for that, unless ALLOWEND is non-nil.
+
+Modifies the match data; use `save-match-data' if necessary."
+  (or subexp (setq subexp 0))
+  (let ((rexp (or separators "[ \f\t\n\r\v]+"))
+	(start 0)
+	notfirst
+	(list nil))
+    (while (and (string-match rexp string
+			      (if (and notfirst
+				       (= start (match-beginning subexp))
+				       (< start (length string)))
+				  (1+ start) start))
+		(< (match-beginning subexp) (length string)))
+      (setq notfirst t)
+      (or (and (not allowbeg) (eq (match-beginning subexp) 0))
+	  (and (eq (match-beginning subexp) (match-end subexp))
+	       (eq (match-beginning subexp) start))
+	  (push (substring string start (match-beginning subexp)) list))
+      (setq start (match-end subexp)))
+    (or (and (not allowend) (eq start (length string)))
+	(push (substring string start) list))
+    (nreverse list)))
+
+(provide 'csv-mode)
+
+;;; csv-mode.el ends here
new file mode 100644
--- /dev/null
+++ b/packages/graphviz-dot-mode.el
@@ -0,0 +1,919 @@
+;;; graphviz-dot-mode.el --- Mode for the dot-language used by graphviz (att).
+
+;; Copyright (C) 2002 - 2005 Pieter Pareit <pieter.pareit@scarlet.be>
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2 of
+;; the License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be
+;; useful, but WITHOUT ANY WARRANTY; without even the implied
+;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+;; PURPOSE.  See the GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public
+;; License along with this program; if not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+;; MA 02111-1307 USA
+
+;; Authors: Pieter Pareit <pieter.pareit@scarlet.be>
+;;          Rubens Ramos <rubensr AT users.sourceforge.net>
+;; Maintainer: Pieter Pareit <pieter.pareit@planetinternet.be>
+;; Homepage: http://users.skynet.be/ppareit/projects/graphviz-dot-mode/graphviz-dot-mode.html
+;; Created: 28 Oct 2002
+;; Last modified: 24 Feb 2005
+;; Version: 0.3.4
+;; Keywords: mode dot dot-language dotlanguage graphviz graphs att
+
+;;; Commentary:
+;; Use this mode for editing files in the dot-language (www.graphviz.org and
+;; http://www.research.att.com/sw/tools/graphviz/).
+;;
+;; To use graphviz-dot-mode, add 
+;; (load-file "PATH_TO_FILE/graphviz-dot-mode.el") 
+;; to your ~/.emacs(.el) or ~/.xemacs/init.el
+;;
+;; The graphviz-dot-mode will do font locking, indentation, preview of graphs
+;; and eases compilation/error location. There is support for both GNU Emacs
+;; and XEmacs.
+;;
+;; Font locking is automatic, indentation uses the same commands as
+;; other modes, tab, M-j and C-M-q.  Insertion of comments uses the
+;; same commands as other modes, M-; .  You can compile a file using
+;; M-x compile or C-c c, after that M-x next-error will also work.
+;; There is support for viewing an generated image with C-c p.
+
+;;; Todo:
+;; * cleanup the mess of graphviz-dot-compilation-parse-errors
+;; * electric indentation is fundamentally broken, because 
+;;   {...} are also used for record nodes. You could argue, I suppose, that 
+;;   many diagrams don't need those, but it would be worth having a note (and 
+;;   it makes sense that the default is now for electric indentation to be 
+;;   off).
+
+;;; History:
+
+;; Version 0.3.4 bug fixes
+;; 24/02/2005: * fixed a bug in graphviz-dot-preview
+;; Version 0.3.3 bug fixes
+;; 13/02/2005: Reuben Thomas <rrt AT sc3d.org>
+;;             * add graphviz-dot-indent-width
+;; Version 0.3.2 bug fixes
+;; 25/03/2004: Rubens Ramos <rubensr AT users.sourceforge.net>
+;;             * semi-colons and brackets are added when electric
+;;               behaviour is disabled.
+;;             * electric characters do not behave electrically inside
+;;               comments or strings.
+;;             * default for electric-braces is disabled now (makes more
+;;               sense I guess).
+;;             * using read-from-minibuffer instead of read-shell-command
+;;               for emacs.
+;;             * Fixed test for easymenu, so that it works on older
+;;               versions of XEmacs.
+;;             * Fixed indentation error when trying to indent last brace
+;;               of an empty graph.
+;;             * region-active-p does not exist in emacs (21.2 at least),
+;;               so removed from code
+;;             * Added uncomment menu option
+;; Version 0.3.1 bug fixes
+;; 03/03/2004: * backward-word needs argument for older emacs
+;; Version 0.3 added features and fixed bugs
+;; 10/01/2004: fixed a bug in graphviz-dot-indent-graph
+;; 08/01/2004: Rubens Ramos <rubensr AT users.sourceforge.net>
+;;             * added customization support
+;;             * Now it works on XEmacs and Emacs
+;;             * Added support to use an external Viewer
+;;             * Now things do not break when dot mode is entered
+;;               when there is no buffer name, but the side effect is
+;;               that in this case, the compilation command is not
+;;               correct.
+;;             * Preview works on XEmacs and emacs.
+;;             * Electric indentation on newline
+;;             * Minor changes to indentation
+;;             * Added keyword completion (but could be A LOT better)
+;;             * There are still a couple of ugly hacks. Look for 'RR'.
+;; Version 0.2 added features
+;; 11/11/2002: added preview support.
+;; 10/11/2002: indent a graph or subgraph at once with C-M-q.
+;; 08/11/2002: relaxed rules for indentation, the may now be extra chars
+;;             after beginning of graph (comment's for example).
+;; Version 0.1.2 bug fixes and naming issues
+;; 06/11/2002: renamed dot-font-lock-defaults to dot-font-lock-keywords.
+;;             added some documentation to dot-colors.
+;;             provided a much better way to handle my max-specpdl-size
+;;             problem.
+;;             added an extra autoload cookie (hope this helps, as I don't
+;;             yet use autoload myself)
+;; Version 0.1.1 bug fixes
+;; 06/11/2002: added an missing attribute, for font-locking to work.
+;;             fixed the regex generating, so that it only recognizes
+;;             whole words
+;; 05/11/2002: there can now be extra white space chars after an '{'.
+;; 04/11/2002: Why I use max-specpdl-size is now documented, and old value
+;;             gets restored.
+;; Version 0.1 initial release
+;; 02/11/2002: implemented parser for *compilation* of a .dot file.
+;; 01/11/2002: implemented compilation of an .dot file.
+;; 31/10/2002: added syntax-table to the mode.
+;; 30/10/2002: implemented indentation code.
+;; 29/10/2002: implemented all of font-lock.
+;; 28/10/2002: derived graphviz-dot-mode from fundamental-mode, started 
+;;             implementing font-lock.
+
+;;; Code:
+
+(defconst graphviz-dot-mode-version "0.3.3"
+  "Version of `graphviz-dot-mode.el'.")
+
+(defgroup graphviz nil
+  "Major mode for editing Graphviz Dot files"
+  :group 'tools)
+
+(defun graphviz-dot-customize ()
+  "Run \\[customize-group] for the `graphviz' group."
+  (interactive)
+  (customize-group 'graphviz))
+
+(defvar graphviz-dot-mode-abbrev-table nil
+  "Abbrev table in use in Graphviz Dot mode buffers.")
+(define-abbrev-table 'graphviz-dot-mode-abbrev-table ())
+
+(defcustom graphviz-dot-dot-program "dot"
+  "*Location of the dot program. This is used by `compile'."
+  :type 'string
+  :group 'graphviz)
+
+(defcustom graphviz-dot-view-command "doted %s"
+  "*External program to run on the buffer. You can use `%s' in this string,
+and it will be substituted by the buffer name."
+  :type 'string
+  :group 'graphviz)
+
+(defcustom graphviz-dot-view-edit-command nil
+  "*Whether to allow the user to edit the command to run an external
+viewer."
+  :type 'boolean
+  :group 'graphviz)
+
+(defcustom graphviz-dot-save-before-view t
+  "*If not nil, M-x graphviz-dot-view saves the current buffer before running
+the command."
+  :type 'boolean
+  :group 'graphviz)
+
+(defcustom graphviz-dot-auto-indent-on-newline t
+  "*If not nil, `electric-graphviz-dot-terminate-line' is executed in a line is terminated."
+  :type 'boolean
+  :group 'graphviz)
+
+(defcustom graphviz-dot-indent-width default-tab-width
+  "*Indentation width in Graphviz Dot mode buffers."
+  :type 'integer
+  :group 'graphviz)
+
+(defcustom graphviz-dot-auto-indent-on-braces nil
+  "*If not nil, `electric-graphviz-dot-open-brace' and `electric-graphviz-dot-close-brace' are executed when { or } are typed"
+  :type 'boolean
+  :group 'graphviz)
+
+(defcustom graphviz-dot-auto-indent-on-semi t
+  "*If not nil, `electric-graphviz-dot-semi' is executed when semicolon is typed"
+  :type 'boolean
+  :group 'graphviz)
+
+(defcustom graphviz-dot-preview-extension "png"
+  "*The extension to use for the compilation and preview commands. The format
+for the compilation command is 
+`dot -T<extension> file.dot > file.<extension>'."
+  :type 'string
+  :group 'graphviz)
+
+(defcustom graphviz-dot-toggle-completions nil
+  "*Non-nil means that repeated use of \
+\\<graphviz-dot-mode-map>\\[graphviz-dot-complete-word] will toggle the possible
+completions in the minibuffer.  Normally, when there is more than one possible
+completion, a buffer will display all completions."
+  :type 'boolean
+  :group 'graphviz)
+
+(defcustom graphviz-dot-delete-completions nil
+  "*Non-nil means that the completion buffer is automatically deleted when a
+key is pressed."
+  :type 'boolean
+  :group 'graphviz)
+
+(defcustom graphviz-dot-attr-keywords 
+  '("graph" "digraph" "subgraph" "node" "edge" "strict" "rankdir"
+    "size" "page" "Damping" "Epsilon" "URL" "arrowhead" "arrowsize"
+    "arrowtail" "bb" "bgcolor" "bottomlabel" "center" "clusterrank"
+    "color" "comment" "compound" "concentrate" "constraint" "decorate"
+    "dim" "dir" "distortion" "fillcolor" "fixedsize" "fontcolor"
+    "fontname" "fontpath" "fontsize" "group" "headURL" "headlabel"
+    "headport" "height" "label" "labelangle" "labeldistance" "labelfloat"
+    "labelfontcolor" "labelfontname" "labelfontsize" "labeljust"
+    "labelloc" "layer" "layers" "len" "lhead" "lp" "ltail" "margin"
+    "maxiter" "mclimit" "minlen" "model" "nodesep" "normalize" "nslimit"
+    "nslimit1" "ordering" "orientation" "overlap" "pack" "pagedir"
+    "pencolor" "peripheries" "pin" "pos" "quantum" "rank" "ranksep"
+    "ratio" "rects" "regular" "remincross" "rotate" "samehead" "sametail"
+    "samplepoint" "searchsize" "sep" "shape" "shapefile" "showboxes"
+    "sides" "skew" "splines" "start" "style" "stylesheet" "tailURL"
+    "taillabel" "tailport" "toplabel" "vertices" "voro_margin" "weight"
+    "z")
+  "*Keywords for attribute names in a graph. This is used by the auto
+completion code. The actual completion tables are built when the mode
+is loaded, so changes to this are not immediately visible."
+  :type '(repeat (string :tag "Keyword"))
+  :group 'graphviz)
+
+(defcustom graphviz-dot-value-keywords 
+  '("true" "false" "normal" "inv" "dot" "invdot" "odot" "invodot"
+    "none" "tee" "empty" "invempty" "diamond" "odiamond" "box" "obox"
+    "open" "crow" "halfopen" "local" "global" "none" "forward" "back"
+    "both" "none" "BL" "BR" "TL" "TR" "RB" "RT" "LB" "LT" ":n" ":ne" ":e"
+    ":se" ":s" ":sw" ":w" ":nw" "same" "min" "source" "max" "sink" "LR"
+    "box" "polygon" "ellipse" "circle" "point" "egg" "triangle"
+    "plaintext" "diamond" "trapezium" "parallelogram" "house" "hexagon"
+    "octagon" "doublecircle" "doubleoctagon" "tripleoctagon" "invtriangle"
+    "invtrapezium" "invhouse" "Mdiamond" "Msquare" "Mcircle" "record"
+    "Mrecord" "dashed" "dotted" "solid" "invis" "bold" "filled"
+    "diagonals" "rounded" ) 
+  "*Keywords for attribute values. This is used by the auto completion
+code. The actual completion tables are built when the mode is loaded,
+so changes to this are not immediately visible."
+  :type '(repeat (string :tag "Keyword")) 
+  :group 'graphviz)
+
+;;; Font-locking:
+(defvar graphviz-dot-colors-list
+  '(aliceblue antiquewhite antiquewhite1 antiquewhite2
+        antiquewhite3 antiquewhite4 aquamarine aquamarine1
+        aquamarine2 aquamarine3 aquamarine4 azure azure1
+        azure2 azure3 azure4 beige bisque bisque1 bisque2
+        bisque3 bisque4 black blanchedalmond blue blue1
+        blue2 blue3 blue4 blueviolet brown brown1 brown2
+        brown3 brown4 burlywood burlywood1 burlywood2
+        burlywood3 burlywood4 cadetblue cadetblue1
+        cadetblue2 cadetblue3 cadetblue4 chartreuse
+        chartreuse1 chartreuse2 chartreuse3 chartreuse4
+        chocolate chocolate1 chocolate2 chocolate3 chocolate4
+        coral coral1 coral2 coral3 coral4 cornflowerblue
+        cornsilk cornsilk1 cornsilk2 cornsilk3 cornsilk4
+        crimson cyan cyan1 cyan2 cyan3 cyan4 darkgoldenrod
+        darkgoldenrod1 darkgoldenrod2 darkgoldenrod3
+        darkgoldenrod4 darkgreen darkkhaki darkolivegreen
+        darkolivegreen1 darkolivegreen2 darkolivegreen3
+        darkolivegreen4 darkorange darkorange1 darkorange2
+        darkorange3 darkorange4 darkorchid darkorchid1
+        darkorchid2 darkorchid3 darkorchid4 darksalmon
+        darkseagreen darkseagreen1 darkseagreen2
+        darkseagreen3 darkseagreen4 darkslateblue
+        darkslategray darkslategray1 darkslategray2
+        darkslategray3  darkslategray4 darkslategrey
+        darkturquoise darkviolet deeppink deeppink1
+        deeppink2 deeppink3 deeppink4 deepskyblue
+        deepskyblue1 deepskyblue2 deepskyblue3 deepskyblue4
+        dimgray dimgrey  dodgerblue dodgerblue1 dodgerblue2
+        dodgerblue3  dodgerblue4 firebrick firebrick1
+        firebrick2 firebrick3 firebrick4 floralwhite
+        forestgreen gainsboro ghostwhite gold gold1 gold2
+        gold3 gold4 goldenrod goldenrod1 goldenrod2
+        goldenrod3 goldenrod4 gray gray0 gray1 gray10 gray100
+        gray11 gray12 gray13 gray14 gray15 gray16 gray17
+        gray18 gray19 gray2 gray20 gray21 gray22 gray23
+        gray24 gray25 gray26 gray27 gray28 gray29 gray3
+        gray30 gray31 gray32 gray33 gray34 gray35 gray36
+        gray37 gray38 gray39 gray4 gray40 gray41 gray42
+        gray43 gray44 gray45 gray46 gray47 gray48 gray49
+        gray5 gray50 gray51 gray52 gray53 gray54 gray55
+        gray56 gray57 gray58 gray59 gray6 gray60 gray61
+        gray62 gray63 gray64 gray65 gray66 gray67 gray68
+        gray69 gray7 gray70 gray71 gray72 gray73 gray74
+        gray75 gray76 gray77 gray78 gray79 gray8 gray80
+        gray81 gray82 gray83 gray84 gray85 gray86 gray87
+        gray88 gray89 gray9 gray90 gray91 gray92 gray93
+        gray94 gray95 gray96 gray97 gray98 gray99 green
+        green1 green2 green3 green4 greenyellow grey grey0
+        grey1 grey10 grey100 grey11 grey12 grey13 grey14
+        grey15 grey16 grey17 grey18 grey19 grey2 grey20
+        grey21 grey22 grey23 grey24 grey25 grey26 grey27
+        grey28 grey29 grey3 grey30 grey31 grey32 grey33
+        grey34 grey35 grey36 grey37 grey38 grey39 grey4
+        grey40 grey41 grey42 grey43 grey44 grey45 grey46
+        grey47 grey48 grey49 grey5 grey50 grey51 grey52
+        grey53 grey54 grey55 grey56 grey57 grey58 grey59
+        grey6 grey60 grey61 grey62 grey63 grey64 grey65
+        grey66 grey67 grey68 grey69 grey7 grey70 grey71
+        grey72 grey73 grey74 grey75 grey76 grey77 grey78
+        grey79 grey8 grey80 grey81 grey82 grey83 grey84
+        grey85 grey86 grey87 grey88 grey89 grey9 grey90
+        grey91 grey92 grey93 grey94 grey95 grey96 grey97
+        grey98 grey99 honeydew honeydew1 honeydew2 honeydew3
+        honeydew4 hotpink hotpink1 hotpink2 hotpink3 hotpink4
+        indianred indianred1 indianred2 indianred3 indianred4
+        indigo ivory ivory1 ivory2 ivory3 ivory4 khaki khaki1
+        khaki2 khaki3 khaki4 lavender lavenderblush
+        lavenderblush1 lavenderblush2 lavenderblush3
+        lavenderblush4 lawngreen lemonchiffon lemonchiffon1
+        lemonchiffon2 lemonchiffon3 lemonchiffon4 lightblue
+        lightblue1 lightblue2 lightblue3 lightblue4
+        lightcoral lightcyan lightcyan1 lightcyan2 lightcyan3
+        lightcyan4 lightgoldenrod lightgoldenrod1
+        lightgoldenrod2 lightgoldenrod3 lightgoldenrod4
+        lightgoldenrodyellow lightgray lightgrey lightpink
+        lightpink1 lightpink2 lightpink3 lightpink4
+        lightsalmon lightsalmon1 lightsalmon2 lightsalmon3
+        lightsalmon4 lightseagreen lightskyblue lightskyblue1
+        lightskyblue2 lightskyblue3 lightskyblue4
+        lightslateblue lightslategray lightslategrey
+        lightsteelblue lightsteelblue1 lightsteelblue2
+        lightsteelblue3 lightsteelblue4 lightyellow
+        lightyellow1 lightyellow2 lightyellow3 lightyellow4
+        limegreen linen magenta magenta1 magenta2 magenta3
+        magenta4 maroon maroon1 maroon2 maroon3 maroon4
+        mediumaquamarine mediumblue  mediumorchid
+        mediumorchid1 mediumorchid2 mediumorchid3
+        mediumorchid4 mediumpurple mediumpurple1
+        mediumpurple2 mediumpurple3 mediumpurple4
+        mediumseagreen mediumslateblue mediumspringgreen
+        mediumturquoise mediumvioletred midnightblue
+        mintcream mistyrose mistyrose1 mistyrose2 mistyrose3
+        mistyrose4 moccasin navajowhite navajowhite1
+        navajowhite2 navajowhite3 navajowhite4 navy navyblue
+        oldlace olivedrab olivedrap olivedrab1 olivedrab2
+        olivedrap3 oragne palegoldenrod palegreen palegreen1
+        palegreen2 palegreen3 palegreen4 paleturquoise
+        paleturquoise1 paleturquoise2 paleturquoise3
+        paleturquoise4 palevioletred palevioletred1
+        palevioletred2 palevioletred3 palevioletred4
+        papayawhip peachpuff peachpuff1 peachpuff2
+        peachpuff3 peachpuff4 peru pink pink1 pink2 pink3
+        pink4 plum plum1 plum2 plum3 plum4 powderblue
+        purple purple1 purple2 purple3 purple4 red red1 red2
+        red3 red4 rosybrown rosybrown1 rosybrown2 rosybrown3
+        rosybrown4 royalblue royalblue1 royalblue2 royalblue3
+        royalblue4 saddlebrown salmon salmon1 salmon2 salmon3
+        salmon4 sandybrown seagreen seagreen1 seagreen2
+        seagreen3 seagreen4 seashell seashell1 seashell2
+        seashell3 seashell4 sienna sienna1 sienna2 sienna3
+        sienna4 skyblue skyblue1 skyblue2 skyblue3 skyblue4
+        slateblue slateblue1 slateblue2 slateblue3 slateblue4
+        slategray slategray1 slategray2 slategray3 slategray4
+        slategrey snow snow1 snow2 snow3 snow4 springgreen
+        springgreen1 springgreen2 springgreen3 springgreen4
+        steelblue steelblue1 steelblue2 steelblue3 steelblue4
+        tan tan1 tan2 tan3 tan4 thistle thistle1 thistle2
+        thistle3 thistle4 tomato tomato1 tomato2 tomato3
+        tomato4 transparent turquoise turquoise1 turquoise2
+        turquoise3 turquoise4 violet violetred violetred1
+        violetred2 violetred3 violetred4 wheat wheat1 wheat2
+        wheat3 wheat4 white whitesmoke yellow yellow1 yellow2
+        yellow3 yellow4 yellowgreen)
+  "Possible color constants in the dot language.
+The list of constant is available at http://www.research.att.com/~erg/graphviz\
+/info/colors.html")
+
+
+(defvar graphviz-dot-color-keywords
+  (mapcar 'symbol-name graphviz-dot-colors-list))
+
+(defvar graphviz-attr-keywords
+  (mapcar '(lambda (elm) (cons elm 0)) graphviz-dot-attr-keywords))
+
+(defvar graphviz-value-keywords
+  (mapcar '(lambda (elm) (cons elm 0)) graphviz-dot-value-keywords))
+
+(defvar graphviz-color-keywords
+  (mapcar '(lambda (elm) (cons elm 0)) graphviz-dot-color-keywords))
+
+;;; Key map
+(defvar graphviz-dot-mode-map ()
+  "Keymap used in Graphviz Dot mode.")
+
+(if graphviz-dot-mode-map
+    ()
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\r"       'electric-graphviz-dot-terminate-line)
+    (define-key map "{"        'electric-graphviz-dot-open-brace)
+    (define-key map "}"        'electric-graphviz-dot-close-brace)
+    (define-key map ";"        'electric-graphviz-dot-semi)
+    (define-key map "\M-\t"    'graphviz-dot-complete-word)
+    (define-key map "\C-\M-q"  'graphviz-dot-indent-graph)
+    (define-key map "\C-cp"    'graphviz-dot-preview)
+    (define-key map "\C-cc"    'compile)
+    (define-key map "\C-cv"    'graphviz-dot-view)
+    (define-key map "\C-c\C-c" 'comment-region)
+    (define-key map "\C-c\C-u" 'graphviz-dot-uncomment-region)
+    (setq graphviz-dot-mode-map map)
+    ))
+
+;;; Syntax table
+(defvar graphviz-dot-mode-syntax-table nil
+  "Syntax table for `graphviz-dot-mode'.")
+
+(if graphviz-dot-mode-syntax-table
+    ()
+  (let ((st (make-syntax-table)))
+    (modify-syntax-entry ?/  ". 124b" st)
+    (modify-syntax-entry ?*  ". 23"   st)
+    (modify-syntax-entry ?\n "> b"    st)
+    (modify-syntax-entry ?=  "."      st)
+    (modify-syntax-entry ?_  "_"      st)
+    (modify-syntax-entry ?-  "_"      st)
+    (modify-syntax-entry ?>  "."      st)
+    (modify-syntax-entry ?[  "("      st)
+    (modify-syntax-entry ?]  ")"      st)
+    (modify-syntax-entry ?\" "\""     st)
+    (setq graphviz-dot-mode-syntax-table st)
+  ))
+
+(defvar graphviz-dot-font-lock-keywords
+  `(("\\(:?di\\|sub\\)?graph \\(\\sw+\\)"
+     (2 font-lock-function-name-face))
+    (,(regexp-opt graphviz-dot-value-keywords 'words)
+     . font-lock-reference-face)
+    ;; to build the font-locking for the colors,
+    ;; we need more room for max-specpdl-size,
+    ;; after that we take the list of symbols,
+    ;; convert them to a list of strings, and make
+    ;; an optimized regexp from them
+    (,(let ((max-specpdl-size (max max-specpdl-size 1200)))
+  (regexp-opt graphviz-dot-color-keywords))
+     . font-lock-string-face)
+    (,(concat
+       (regexp-opt graphviz-dot-attr-keywords 'words)
+       "[ \\t\\n]*=")
+     ;; RR - ugly, really, but I dont know why xemacs does not work
+     ;; if I change the next car to "1"...
+     (0 font-lock-variable-name-face)))
+  "Keyword highlighting specification for `graphviz-dot-mode'.")
+
+;;;###autoload
+(defun graphviz-dot-mode ()
+  "Major mode for the dot language. \\<graphviz-dot-mode-map> 
+TAB indents for graph lines. 
+
+\\[graphviz-dot-indent-graph]\t- Indentaion function.
+\\[graphviz-dot-preview]\t- Previews graph in a buffer.
+\\[graphviz-dot-view]\t- Views graph in an external viewer.
+\\[graphviz-dot-indent-line]\t- Indents current line of code.
+\\[graphviz-dot-complete-word]\t- Completes the current word.
+\\[electric-graphviz-dot-terminate-line]\t- Electric newline.
+\\[electric-graphviz-dot-open-brace]\t- Electric open braces.
+\\[electric-graphviz-dot-close-brace]\t- Electric close braces.
+\\[electric-graphviz-dot-semi]\t- Electric semi colons.
+
+Variables specific to this mode:
+
+  graphviz-dot-dot-program            (default `dot')
+       Location of the dot program.
+  graphviz-dot-view-command           (default `doted %s')
+       Command to run when `graphviz-dot-view' is executed.
+  graphviz-dot-view-edit-command      (default nil)
+       If the user should be asked to edit the view command.
+  graphviz-dot-save-before-view       (default t)
+       Automatically save current buffer berore `graphviz-dot-view'.
+  graphviz-dot-preview-extension      (default `png')
+       File type to use for `graphviz-dot-preview'.
+  graphviz-dot-auto-indent-on-newline (default t)
+       Whether to run `electric-graphviz-dot-terminate-line' when 
+       newline is entered.
+  graphviz-dot-auto-indent-on-braces (default t)
+       Whether to run `electric-graphviz-dot-open-brace' and
+       `electric-graphviz-dot-close-brace' when braces are 
+       entered.
+  graphviz-dot-auto-indent-on-semi (default t)
+       Whether to run `electric-graphviz-dot-semi' when semi colon
+       is typed.
+  graphviz-dot-toggle-completions  (default nil)
+       If completions should be displayed in the buffer instead of a
+       completion buffer when \\[graphviz-dot-complete-word] is
+       pressed repeatedly.
+
+This mode can be customized by running \\[graphviz-dot-customize].
+
+Turning on Graphviz Dot mode calls the value of the variable 
+`graphviz-dot-mode-hook' with no args, if that value is non-nil."
+  (interactive)
+  (kill-all-local-variables)
+  (use-local-map graphviz-dot-mode-map)
+  (setq major-mode 'graphviz-dot-mode)
+  (setq mode-name "dot")
+  (setq local-abbrev-table graphviz-dot-mode-abbrev-table)
+  (set-syntax-table graphviz-dot-mode-syntax-table)
+  (set (make-local-variable 'indent-line-function) 'graphviz-dot-indent-line)
+  (set (make-local-variable 'comment-start) "//")
+  (set (make-local-variable 'comment-start-skip) "/\\*+ *\\|//+ *")
+  (set (make-local-variable 'font-lock-defaults) 
+       '(graphviz-dot-font-lock-keywords))
+  ;; RR - If user is running this in the scratch buffer, there is no
+  ;; buffer file name...
+  (if (buffer-file-name)
+      (set (make-local-variable 'compile-command) 
+       (concat graphviz-dot-dot-program
+               " -T" graphviz-dot-preview-extension " "
+               buffer-file-name
+               " > "
+               (file-name-sans-extension
+                buffer-file-name)
+               "." graphviz-dot-preview-extension)))
+  (set (make-local-variable 'compilation-parse-errors-function)
+       'graphviz-dot-compilation-parse-errors)
+  (if dot-menu
+      (easy-menu-add dot-menu))
+  (run-hooks 'graphviz-dot-mode-hook)
+  )
+
+;;;; Menu definitions
+
+(defvar dot-menu nil
+  "Menu for Graphviz Dot Mode.
+This menu will get created automatically if you have the `easymenu'
+package. Note that the latest X/Emacs releases contain this package.")
+
+(and (condition-case nil
+         (require 'easymenu)
+       (error nil))
+     (easy-menu-define
+      dot-menu graphviz-dot-mode-map "Graphviz Mode menu"
+      '("Graphviz"
+        ["Indent Graph"       graphviz-dot-indent-graph     t]
+        ["Comment Out Region" comment-region                (mark)]
+        ["Uncomment Region"   graphviz-dot-uncomment-region (mark)]
+        "-"
+        ["Compile"            compile                       t]
+        ["Preview"            graphviz-dot-preview        
+         (and (buffer-file-name)
+              (not (buffer-modified-p)))]
+        ["External Viewer"    graphviz-dot-view             (buffer-file-name)]
+        "-"
+        ["Customize..."       graphviz-dot-customize        t]
+        )))
+
+;;;; Compilation
+
+;; note on graphviz-dot-compilation-parse-errors:
+;;  It would nicer if we could just use compilation-error-regexp-alist
+;;  to do that, 3 options:
+;;   - still write dot-compilation-parse-errors, don't build
+;;     a return list, but modify the *compilation* buffer
+;;     in a way compilation-error-regexp-alist recognizes the
+;;     format.
+;;     to do that, I should globally change compilation-parse-function
+;;     to this function, and call the old value of comp..-parse-fun..
+;;     to provide the return value.
+;;     two drawbacks are that, every compilation would be run through
+;;     this function (performance) and that in autoload there would
+;;     be a chance that this function would not yet be known.
+;;   - let the compilation run through a filter that would
+;;     modify the output of dot or neato:
+;;     dot -Tpng input.dot | filter
+;;     drawback: ugly, extra work for user, extra decency ...
+;;               no-option
+;;   - modify dot and neato !!! (PP:15/02/2005 seems to have happend,
+;;                                       so version 0.4.0 should clean this mess up!)
+(defun graphviz-dot-compilation-parse-errors (limit-search find-at-least)
+  "Parse the current buffer for dot errors.
+See variable `compilation-parse-errors-functions' for interface."
+  (interactive)
+  (save-excursion
+    (set-buffer "*compilation*")
+    (goto-char (point-min))
+    (setq compilation-error-list nil)
+    (let (buffer-of-error)
+      (while (not (eobp))
+  (cond
+   ((looking-at "^dot\\( -[^ ]+\\)* \\(.*\\)")
+    (setq buffer-of-error (find-file-noselect
+         (buffer-substring-no-properties
+          (nth 4 (match-data t))
+          (nth 5 (match-data t))))))
+   ((looking-at ".*:.*line \\([0-9]+\\)")
+    (let ((line-of-error
+     (string-to-number (buffer-substring-no-properties
+            (nth 2 (match-data t))
+            (nth 3 (match-data t))))))
+      (setq compilation-error-list
+      (cons
+       (cons
+        (point-marker)
+        (save-excursion
+          (set-buffer buffer-of-error)
+          (goto-line line-of-error)
+          (beginning-of-line)
+          (point-marker)))
+       compilation-error-list))))
+    (t t))
+  (forward-line 1)) )))
+
+;;;;
+;;;; Indentation
+;;;;
+(defun graphviz-dot-uncomment-region (begin end)
+	"Uncomments a region of code."
+	(interactive "r")
+	(comment-region begin end '(4)))
+
+(defun graphviz-dot-indent-line ()
+  "Indent current line of dot code."
+  (interactive)
+  (if (bolp)
+      (graphviz-dot-real-indent-line)
+    (save-excursion
+      (graphviz-dot-real-indent-line))))
+        
+(defun graphviz-dot-real-indent-line ()
+  "Indent current line of dot code."
+  (beginning-of-line)
+  (cond
+   ((bobp)
+    ;; simple case, indent to 0
+    (indent-line-to 0))
+   ((looking-at "^[ \t]*}[ \t]*$")
+    ;; block closing, deindent relative to previous line
+    (indent-line-to (save-excursion
+                      (forward-line -1)
+                      (max 0 (- (current-indentation) graphviz-dot-indent-width)))))
+   ;; other cases need to look at previous lines
+   (t
+    (indent-line-to (save-excursion
+                      (forward-line -1)
+                      (cond
+                       ((looking-at "\\(^.*{[^}]*$\\)")
+                        ;; previous line opened a block
+                        ;; indent to that line
+                        (+ (current-indentation) graphviz-dot-indent-width))
+                       ((and (not (looking-at ".*\\[.*\\].*"))
+                             (looking-at ".*\\[.*")) ; TODO:PP : can be 1 regex
+                        ;; previous line started filling
+                        ;; attributes, intend to that start
+                        (search-forward "[")
+                        (current-column))
+                       ((and (not (looking-at ".*\\[.*\\].*"))
+                             (looking-at ".*\\].*")) ; TODO:PP : "
+                        ;; previous line stopped filling
+                        ;; attributes, find the line that started
+                        ;; filling them and indent to that line
+                        (while (or (looking-at ".*\\[.*\\].*")
+                                   (not (looking-at ".*\\[.*"))) ; TODO:PP : "
+                          (forward-line -1))
+                        (current-indentation))
+                       (t
+                        ;; default case, indent the
+                        ;; same as previous line
+                        (current-indentation)) ))) )))
+
+(defun graphviz-dot-indent-graph ()
+  "Indent the graph/digraph/subgraph where point is at.
+This will first teach the beginning of the graph were point is at, and
+then indent this and each subgraph in it."
+  (interactive)
+  (save-excursion
+    ;; position point at start of graph
+    (while (not (or (looking-at "\\(^.*{[^}]*$\\)") (bobp)))
+      (forward-line -1))
+    ;; bracket { one +; bracket } one -
+    (let ((bracket-count 0))
+      (while
+          (progn
+            (cond
+             ;; update bracket-count
+             ((looking-at "\\(^.*{[^}]*$\\)")
+              (setq bracket-count (+ bracket-count 1)))
+             ;; update bracket-count
+             ((looking-at "^[ \t]*}[ \t]*$")
+              (setq bracket-count (- bracket-count 1))))
+            ;; indent this line and move on
+            (graphviz-dot-indent-line)
+            (forward-line 1)
+            ;; as long as we are not completed or at end of buffer
+            (and (> bracket-count 0) (not (eobp))))))))
+     
+;;;;
+;;;; Electric indentation
+;;;;
+(defun graphviz-dot-comment-or-string-p ()
+  (let ((state (parse-partial-sexp (point-min) (point))))
+     (or (nth 4 state) (nth 3 state))))
+
+(defun graphviz-dot-newline-and-indent ()
+  (save-excursion
+    (beginning-of-line)
+    (skip-chars-forward " \t")
+    (graphviz-dot-indent-line))
+  (delete-horizontal-space)
+  (newline)
+  (graphviz-dot-indent-line))
+
+(defun electric-graphviz-dot-terminate-line ()
+  "Terminate line and indent next line."
+  (interactive)
+  (if graphviz-dot-auto-indent-on-newline
+      (graphviz-dot-newline-and-indent)
+    (newline)))
+
+(defun electric-graphviz-dot-open-brace ()
+  "Terminate line and indent next line."
+  (interactive)
+  (insert "{")
+  (if (and graphviz-dot-auto-indent-on-braces
+           (not (graphviz-dot-comment-or-string-p)))
+      (graphviz-dot-newline-and-indent)))
+
+(defun electric-graphviz-dot-close-brace ()
+  "Terminate line and indent next line."
+  (interactive)
+  (insert "}")
+  (if (and graphviz-dot-auto-indent-on-braces
+           (not (graphviz-dot-comment-or-string-p)))
+      (progn
+        (save-excursion
+          (beginning-of-line)
+          (skip-chars-forward " \t")
+          (graphviz-dot-indent-line))
+        (newline)
+        (graphviz-dot-indent-line))))
+
+(defun electric-graphviz-dot-semi ()
+  "Terminate line and indent next line."
+  (interactive)
+  (insert ";")
+  (if (and graphviz-dot-auto-indent-on-semi
+           (not (graphviz-dot-comment-or-string-p)))
+      (graphviz-dot-newline-and-indent)))
+
+;;;;
+;;;; Preview
+;;;;
+(defun graphviz-dot-preview ()
+  "Shows an example of the current dot file in an emacs buffer.
+This assumes that we are running GNU Emacs or XEmacs under a windowing system.
+See `image-file-name-extensions' for customizing the files that can be
+loaded in GNU Emacs, and `image-formats-alist' for XEmacs."
+  (interactive)
+  ;; unsafe to compile ourself, ask it to the user
+  (if (buffer-modified-p)
+      (message "Buffer needs to be compiled.")
+    (if (string-match "XEmacs" emacs-version)
+        ;; things are easier in XEmacs...
+        (find-file-other-window (concat (file-name-sans-extension
+					 buffer-file-name)
+					"." graphviz-dot-preview-extension))
+      ;; run through all the extensions for images
+      (let ((l image-file-name-extensions))
+        (while
+            (let ((f (concat (file-name-sans-extension (buffer-file-name))
+                             "."
+                             (car l))))
+              ;; see if a file matches, might be best also to check
+              ;; if file is up to date TODO:PP
+              (if (file-exists-p f)
+                  (progn (auto-image-file-mode 1)
+                         ;; OK, this is ugly, I would need to 
+                         ;; know how I can reload a file in an existing buffer
+                         (if (get-buffer "*preview*")
+                             (kill-buffer "*preview*"))
+                         (set-buffer (find-file-noselect f))
+                         (rename-buffer "*preview*")
+                         (display-buffer (get-buffer "*preview*"))
+                         ;; stop iterating
+                         '())
+                ;; will stop iterating when l is nil
+                (setq l (cdr l)))))
+      ;; each extension tested and nothing found, let user know
+      (when (eq l '())
+        (message "No image found."))))))
+
+;;;;
+;;;; View
+;;;;
+(defun graphviz-dot-view ()
+  "Runs an external viewer. This creates an external process every time it
+is executed. If `graphviz-dot-save-before-view' is set, the current
+buffer is saved before the command is executed."
+  (interactive)
+  (let ((cmd (if graphviz-dot-view-edit-command
+                 (if (string-match "XEmacs" emacs-version)
+                     (read-shell-command "View command: " 
+                                         (format graphviz-dot-view-command
+                                                 (buffer-file-name)))
+                   (read-from-minibuffer "View command: " 
+                                         (format graphviz-dot-view-command
+                                                 (buffer-file-name))))
+               (format graphviz-dot-view-command (buffer-file-name)))))
+    (if graphviz-dot-save-before-view 
+        (save-buffer))
+    (setq novaproc (start-process-shell-command
+                    (downcase mode-name) nil cmd))
+    (message (format "Executing `%s'..." cmd))))
+
+;;;;
+;;;; Completion
+;;;;
+(defvar graphviz-dot-str nil)
+(defvar graphviz-dot-all nil)
+(defvar graphviz-dot-pred nil)
+(defvar graphviz-dot-buffer-to-use nil)
+(defvar graphviz-dot-flag nil)
+
+(defun graphviz-dot-get-state ()
+  "Returns the syntax state of the current point."
+  (let ((state (parse-partial-sexp (point-min) (point))))
+    (cond
+     ((nth 4 state) 'comment)
+     ((nth 3 state) 'string)
+     ((not (nth 1 state)) 'out)
+     (t (save-excursion
+          (skip-chars-backward "^[,=\\[]{};")
+          (backward-char)
+          (cond 
+           ((looking-at "[\\[,]{};") 'attribute)
+           ((looking-at "=") (progn
+                               (backward-word 1)
+                               (if (looking-at "[a-zA-Z]*color")
+                                   'color
+                                 'value)))
+           (t 'other)))))))
+
+(defun graphviz-dot-get-keywords ()
+  "Return possible completions for a word"
+  (let ((state (graphviz-dot-get-state)))
+    (cond
+     ((equal state 'comment)   ())
+     ((equal state 'string)    ())
+     ((equal state 'out)       graphviz-attr-keywords)
+     ((equal state 'value)     graphviz-value-keywords)
+     ((equal state 'color)     graphviz-color-keywords)
+     ((equal state 'attribute) graphviz-attr-keywords)
+     (t                        graphviz-attr-keywords))))
+
+(defvar graphviz-dot-last-word-numb 0)
+(defvar graphviz-dot-last-word-shown nil)
+(defvar graphviz-dot-last-completions nil)
+
+(defun graphviz-dot-complete-word ()
+  "Complete word at current point."
+  (interactive)
+  (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point)))
+         (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point)))
+         (graphviz-dot-str (buffer-substring b e))
+         (allcomp (if (and graphviz-dot-toggle-completions
+                           (string= graphviz-dot-last-word-shown 
+                                    graphviz-dot-str))
+                      graphviz-dot-last-completions
+                    (all-completions graphviz-dot-str 
+                                     (graphviz-dot-get-keywords))))
+         (match (if graphviz-dot-toggle-completions
+                    "" (try-completion
+                        graphviz-dot-str (mapcar '(lambda (elm)
+                                                    (cons elm 0)) allcomp)))))
+    ;; Delete old string
+    (delete-region b e)
+    
+    ;; Toggle-completions inserts whole labels
+    (if graphviz-dot-toggle-completions
+        (progn
+          ;; Update entry number in list
+          (setq graphviz-dot-last-completions allcomp
+                graphviz-dot-last-word-numb 
+                (if (>= graphviz-dot-last-word-numb (1- (length allcomp)))
+                    0
+                  (1+ graphviz-dot-last-word-numb)))
+          (setq graphviz-dot-last-word-shown 
+                (elt allcomp graphviz-dot-last-word-numb))
+          ;; Display next match or same string if no match was found
+          (if (not (null allcomp))
+              (insert "" graphviz-dot-last-word-shown)
+            (insert "" graphviz-dot-str)
+            (message "(No match)")))
+      ;; The other form of completion does not necessarily do that.
+      
+      ;; Insert match if found, or the original string if no match
+      (if (or (null match) (equal match 't))
+          (progn (insert "" graphviz-dot-str)
+                 (message "(No match)"))
+        (insert "" match))
+      ;; Give message about current status of completion
+      (cond ((equal match 't)
+             (if (not (null (cdr allcomp)))
+                 (message "(Complete but not unique)")
+               (message "(Sole completion)")))
+            ;; Display buffer if the current completion didn't help 
+            ;; on completing the label.
+            ((and (not (null (cdr allcomp))) (= (length graphviz-dot-str)
+                                                (length match)))
+             (with-output-to-temp-buffer "*Completions*"
+               (display-completion-list allcomp))
+             ;; Wait for a keypress. Then delete *Completion*  window
+             (momentary-string-display "" (point))
+             (if graphviz-dot-delete-completions
+                 (delete-window 
+                  (get-buffer-window (get-buffer "*Completions*"))))
+             )))))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.dot\\'" . graphviz-dot-mode))
+
+;;; graphviz-dot-mode.el ends here
+
new file mode 100644
--- /dev/null
+++ b/packages/markdown-mode.el
@@ -0,0 +1,1470 @@
+;;; markdown-mode.el --- Major mode to edit Markdown files in Emacs
+
+;; Copyright (C) 2007, 2008, 2009 Jason Blevins
+
+;; Version: 1.7
+;; Keywords: Markdown major mode
+;; Author: Jason Blevins <jrblevin@sdf.lonestar.org>
+;; URL: http://jblevins.org/projects/markdown-mode/
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; markdown-mode is a major mode for editing [Markdown][]-formatted
+;; text files in GNU Emacs.  markdown-mode is free software, licensed
+;; under the GNU GPL.
+;;
+;;  [Markdown]: http://daringfireball.net/projects/markdown/
+;;
+;; The latest stable version is markdown-mode 1.7, released on October 1, 2009:
+;;
+;;    * [markdown-mode.el][]
+;;    * [Screenshot][]
+;;    * [Release notes][]
+;;
+;; markdown-mode is also available in the Debian
+;; [emacs-goodies-el](http://packages.debian.org/emacs-goodies-el)
+;; package (beginning with revision 27.0-1) and the OpenBSD
+;; [textproc/markdown-mode](http://pkgsrc.se/textproc/markdown-mode) package.
+;;
+;;  [markdown-mode.el]: http://jblevins.org/projects/markdown-mode/markdown-mode.el
+;;  [screenshot]: http://jblevins.org/projects/markdown-mode/screenshots/20080604-001.png
+;;  [release notes]: http://jblevins.org/projects/markdown-mode/rev-1-7
+
+;; The latest development version can be downloaded directly
+;; ([markdown-mode.el][devel.el]) or it can be obtained from the
+;; (browsable and clonable) Git repository at
+;; <http://jblevins.org/git/markdown-mode.git>.  The entire repository,
+;; including the full project history, can be cloned via the Git protocol
+;; by running
+;;
+;;     git clone git://jblevins.org/git/markdown-mode.git
+;;
+;;  [devel.el]: http://jblevins.org/git/markdown-mode.git/plain/markdown-mode.el
+
+;;; Dependencies:
+
+;; markdown-mode requires easymenu, a standard package since GNU Emacs
+;; 19 and XEmacs 19, which provides a uniform interface for creating
+;; menus in GNU Emacs and XEmacs.
+
+;;; Installation:
+
+;; Make sure to place `markdown-mode.el` somewhere in the load-path and add
+;; the following lines to your `.emacs` file to associate markdown-mode
+;; with `.text` files:
+;;
+;;     (autoload 'markdown-mode "markdown-mode.el"
+;;        "Major mode for editing Markdown files" t)
+;;     (setq auto-mode-alist
+;;        (cons '("\\.text" . markdown-mode) auto-mode-alist))
+;;
+;; There is no consensus on an official file extension so change `.text` to
+;; `.mdwn`, `.md`, `.mdt`, or whatever you call your markdown files.
+
+;;; Customization:
+
+;; Although no configuration is *necessary* there are a few things
+;; that can be customized.  The `M-x customize-mode` command
+;; provides an interface to all of the possible customizations:
+;;
+;;   * `markdown-command` - the command used to run Markdown
+;;     (default: `markdown`).
+;;
+;;   * `markdown-hr-length` - the length of horizontal rules
+;;     (default: `5`).
+;;
+;;   * `markdown-bold-underscore` - set to a non-nil value to use two
+;;     underscores for bold instead of two asterisks (default: `nil`).
+;;
+;;   * `markdown-italic-underscore` - set to a non-nil value to use
+;;     underscores for italic instead of asterisks (default: `nil`).
+;;
+;;   * `markdown-indent-function` - the function to use for automatic
+;;     indentation (default: `markdown-indent-line`).
+;;
+;;   * `markdown-indent-on-enter` - set to a non-nil value to
+;;     automatically indent new lines when the enter key is pressed
+;;     (default: `t`)
+;;
+;;   * `markdown-uri-types` - a list of protocols for URIs that
+;;     `markdown-mode' should highlight.
+;;
+;;   * `markdown-enable-math` - syntax highlighting for
+;;     LaTeX fragments (default: `nil`).
+;;
+;; Additionally, the faces used for syntax highlighting can be modified to
+;; your liking by issuing `M-x customize-group RET markdown-faces`
+;; or by using the "Markdown Faces" link at the bottom of the mode
+;; customization screen.
+
+;;; Usage:
+
+;; Keybindings are grouped by prefixes based on their function.  For
+;; example, commands dealing with headers begin with `C-c C-t`.  The
+;; primary commands in each group will are described below.  You can
+;; obtain a list of all keybindings by pressing `C-c C-h`.
+;;
+;;   * Anchors: `C-c C-a`
+;;
+;;     `C-c C-a l` inserts inline links of the form `[text](url)`.  If
+;;     there is an active region, text in the region is used for the
+;;     link text.  `C-c C-a w` acts similarly for wiki links of the
+;;     form `[[WikiLink]]`.
+;;
+;;   * Commands: `C-c C-c`
+;;
+;;     `C-c C-c m` will run Markdown on the current buffer and preview
+;;     the output in another buffer while `C-c C-c p` runs Markdown on
+;;     the current buffer and previews the output in a browser.
+;;
+;;     `C-c C-c c` will check for undefined references.  If there are
+;;     any, a small buffer will open with a list of undefined
+;;     references and the line numbers on which they appear.  In Emacs
+;;     22 and greater, selecting a reference from this list and
+;;     pressing `RET` will insert an empty reference definition at the
+;;     end of the buffer.  Similarly, selecting the line number will
+;;     jump to the corresponding line.
+;;
+;;   * Images: `C-c C-i`
+;;
+;;     `C-c C-i i` inserts an image, using the active region (if any)
+;;     as the alt text.
+;;
+;;   * Physical styles: `C-c C-p`
+;;
+;;     These commands all act on text in the active region, if any,
+;;     and insert empty markup fragments otherwise.  `C-c C-p b` makes
+;;     the selected text bold, `C-c C-p f` formats the region as
+;;     fixed-width text, and `C-c C-p i` is used for italic text.
+;;
+;;   * Logical styles: `C-c C-s`
+;;
+;;     These commands all act on text in the active region, if any,
+;;     and insert empty markup fragments otherwise.  Logical styles
+;;     include blockquote (`C-c C-s b`), preformatted (`C-c C-s p`),
+;;     code (`C-c C-s c`), emphasis (`C-c C-s e`), and strong (`C-c
+;;     C-s s`).
+;;
+;;   * Headers: `C-c C-t`
+;;
+;;     All header commands use text in the active region, if any, as
+;;     the header text.  To insert an atx or hash style level-n
+;;     header, press `C-c C-t n` where n is between 1 and 6.  For a
+;;     top-level setext or underline style header press `C-c C-t t`
+;;     (mnemonic: title) and for a second-level underline-style header
+;;     press `C-c C-t s` (mnemonic: section).
+;;
+;;   * Other commands
+;;
+;;     `C-c -` inserts a horizontal rule.
+;;
+;; Many of the commands described above behave differently depending on
+;; whether Transient Mark mode is enabled or not.  When it makes sense,
+;; if Transient Mark mode is on and a region is active, the command
+;; applies to the text in the region (e.g., `C-c C-p b` makes the region
+;; bold).  For users who prefer to work outside of Transient Mark mode,
+;; in Emacs 22 it can be enabled temporarily by pressing `C-SPC C-SPC`.
+;;
+;; When applicable, commands that specifically act on the region even
+;; outside of Transient Mark mode have the same keybinding as the with
+;; the exception of an additional `C-` prefix.  For example,
+;; `markdown-insert-blockquote` is bound to `C-c C-s b` and only acts on
+;; the region in Transient Mark mode while `markdown-blockquote-region`
+;; is bound to `C-c C-s C-b` and always applies to the region (when
+;; nonempty).
+;;
+;; markdown-mode supports outline-minor-mode as well as org-mode-style
+;; visibility cycling for atx- or hash-style headers.  There are two
+;; types of visibility cycling: Pressing `S-TAB` cycles globally between
+;; the table of contents view (headers only), outline view (top-level
+;; headers only), and the full document view.  Pressing `TAB` while the
+;; point is at a header will cycle through levels of visibility for the
+;; subtree: completely folded, visible children, and fully visible.
+;; Note that mixing hash and underline style headers will give undesired
+;; results.
+
+;;; Extensions:
+
+;; Besides supporting the basic Markdown syntax, markdown-mode also
+;; includes syntax highlighting for `[[Wiki Links]]` by default.
+;;
+;; [SmartyPants][] support is possible by customizing `markdown-command`.
+;; If you install `SmartyPants.pl` at, say, `/usr/local/bin/smartypants`,
+;; then you can set `markdown-command` to `"markdown | smartypants"`.
+;; You can do this either by using `M-x customize-group markdown`
+;; or by placing the following in your `.emacs` file:
+;;
+;;     (defun markdown-custom ()
+;;       "markdown-mode-hook"
+;;       (setq markdown-command "markdown | smartypants"))
+;;     (add-hook 'markdown-mode-hook '(lambda() (markdown-custom)))
+;;
+;; [SmartyPants]: http://daringfireball.net/projects/smartypants/
+;;
+;; Experimental syntax highlighting for mathematical expressions written
+;; in LaTeX (only expressions denoted by `$..$`, `$$..$$`, or `\[..\]`)
+;; can be enabled by setting `markdown-enable-math` to a non-nil value,
+;; either via customize or by placing `(setq markdown-enable-itex t)`
+;; in `.emacs`, and restarting Emacs.
+
+;;; Acknowledgments:
+
+;; markdown-mode has benefited greatly from the efforts of the
+;; following people:
+;;
+;;   * Cyril Brulebois <cyril.brulebois@enst-bretagne.fr> for Debian packaging.
+;;   * Conal Elliott <conal@conal.net> for a font-lock regexp patch.
+;;   * Edward O'Connor <hober0@gmail.com> for a font-lock regexp fix.
+;;   * Greg Bognar <greg_bognar@hms.harvard.edu> for menus and a patch.
+;;   * Daniel Burrows <dburrows@debian.org> for filing Debian bug #456592.
+;;   * Peter S. Galbraith <psg@debian.org> for maintaining emacs-goodies-el.
+;;   * Dmitry Dzhus <mail@sphinx.net.ru> for reference checking functions.
+;;   * Bryan Kyle <bryan.kyle@gmail.com> for indentation code.
+;;   * intrigeri <intrigeri@boum.org> for face customizations.
+;;   * Ankit Solanki <ankit.solanki@gmail.com> for longlines.el compatibility.
+;;   * Hilko Bengen <bengen@debian.org> for proper XHTML output.
+;;   * Jose A. Ortega Ruiz <jao@gnu.org> for Emacs 23 fixes.
+;;   * Alec Resnick <alec@sproutward.org> for bug reports.
+;;   * Peter Williams <pezra@barelyenough.org> for fill-paragraph enhancements.
+
+;;; Bugs:
+
+;; Although markdown-mode is developed and tested primarily using
+;; GNU Emacs 23, compatibility with GNU Emacs 21 and 22 is also a
+;; priority.
+;;
+;; markdown-mode's syntax highlighting is accomplished using the
+;; search-based fontification features of Emacs through a series of
+;; regular expressions.  Unfortunately, Emacs has trouble highlighting
+;; multi-line constructs using regular expressions and this creates
+;; several syntax-highlighting quirks such as mistaking indented
+;; lists for preformatted text, etc.  Making markdown-mode's syntax
+;; highlighting more robust through the use of matching functions
+;; or syntactic font lock is a high-priority item for future work.
+;;
+;; If you find any bugs not mentioned here, please construct a test
+;; case and/or a patch and email me at <jrblevin@sdf.lonestar.org>.
+
+;;; History:
+
+;; markdown-mode was written and is maintained by Jason Blevins.  The
+;; first version was released on May 24, 2007.
+;;
+;;   * 2007-05-24: Version 1.1
+;;   * 2007-05-25: Version 1.2
+;;   * 2007-06-05: [Version 1.3][]
+;;   * 2007-06-29: Version 1.4
+;;   * 2008-05-24: [Version 1.5][]
+;;   * 2008-06-04: [Version 1.6][]
+;;   * 2008-10-01: [Version 1.7][]
+;;
+;; [Version 1.3]: http://jblevins.org/projects/markdown-mode/rev-1-3
+;; [Version 1.5]: http://jblevins.org/projects/markdown-mode/rev-1-5
+;; [Version 1.6]: http://jblevins.org/projects/markdown-mode/rev-1-6
+;; [Version 1.7]: http://jblevins.org/projects/markdown-mode/rev-1-7
+
+
+
+
+;;; Code:
+
+(require 'easymenu)
+(require 'outline)
+
+
+;;; Customizable variables ====================================================
+
+;; Current revision
+(defconst markdown-mode-version "1.7-dev")
+
+;; A hook for users to run their own code when the mode is loaded.
+(defvar markdown-mode-hook nil)
+
+
+;;; Customizable variables ====================================================
+
+(defgroup markdown nil
+  "Major mode for editing text files in Markdown format."
+  :prefix "markdown-"
+  :group 'wp
+  :link '(url-link "http://jblevins.org/projects/markdown-mode/"))
+
+(defcustom markdown-command "markdown"
+  "Command to run markdown."
+  :group 'markdown
+  :type 'string)
+
+(defcustom markdown-hr-length 5
+  "Length of horizonal rules."
+  :group 'markdown
+  :type 'integer)
+
+(defcustom markdown-bold-underscore nil
+  "Use two underscores for bold instead of two asterisks."
+  :group 'markdown
+  :type 'boolean)
+
+(defcustom markdown-italic-underscore nil
+  "Use underscores for italic instead of asterisks."
+  :group 'markdown
+  :type 'boolean)
+
+(defcustom markdown-indent-function 'markdown-indent-line
+  "Function to use to indent."
+  :group 'markdown
+  :type 'function)
+
+(defcustom markdown-indent-on-enter t
+  "Automatically indent new lines when enter key is pressed."
+  :group 'markdown
+  :type 'boolean)
+
+(defcustom markdown-uri-types
+  '("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")
+  "Link types for syntax highlighting of URIs."
+  :group 'markdown
+  :type 'list)
+
+(defcustom markdown-enable-math nil
+  "Syntax highlighting for inline LaTeX expressions.
+This will not take effect until Emacs is restarted."
+  :group 'markdown
+  :type 'boolean)
+
+(defcustom markdown-css-path nil
+  "CSS file to include in the output XHTML"
+  :group 'markdown
+  :type 'string)
+
+;;; Font lock =================================================================
+
+(require 'font-lock)
+
+
+(defvar markdown-italic-face 'markdown-italic-face
+  "Face name to use for italic text.")
+
+(defvar markdown-bold-face 'markdown-bold-face
+  "Face name to use for bold text.")
+
+(defvar markdown-header-face 'markdown-header-face
+  "Face name to use as a base for headers.")
+
+(defvar markdown-header-face-1 'markdown-header-face-1
+  "Face name to use for level-1 headers.")
+
+(defvar markdown-header-face-2 'markdown-header-face-2
+  "Face name to use for level-2 headers.")
+
+(defvar markdown-header-face-3 'markdown-header-face-3
+  "Face name to use for level-3 headers.")
+
+(defvar markdown-header-face-4 'markdown-header-face-4
+  "Face name to use for level-4 headers.")
+
+(defvar markdown-header-face-5 'markdown-header-face-5
+  "Face name to use for level-5 headers.")
+
+(defvar markdown-header-face-6 'markdown-header-face-6
+  "Face name to use for level-6 headers.")
+
+(defvar markdown-inline-code-face 'markdown-inline-code-face
+  "Face name to use for inline code.")
+
+(defvar markdown-list-face 'markdown-list-face
+  "Face name to use for list markers.")
+
+(defvar markdown-blockquote-face 'markdown-blockquote-face
+  "Face name to use for blockquote.")
+
+(defvar markdown-pre-face 'markdown-pre-face
+  "Face name to use for preformatted text.")
+
+(defvar markdown-link-face 'markdown-link-face
+  "Face name to use for links.")
+
+(defvar markdown-reference-face 'markdown-reference-face
+  "Face name to use for reference.")
+
+(defvar markdown-url-face 'markdown-url-face
+  "Face name to use for URLs.")
+
+(defvar markdown-link-title-face 'markdown-link-title-face
+  "Face name to use for reference link titles.")
+
+(defvar markdown-comment-face 'markdown-comment-face
+  "Face name to use for HTML comments.")
+
+(defvar markdown-math-face 'markdown-math-face
+  "Face name to use for LaTeX expressions.")
+
+
+(defgroup markdown-faces nil
+  "Faces used in Markdown Mode"
+  :group 'markdown
+  :group 'faces)
+
+(defface markdown-italic-face
+  '((t :inherit font-lock-variable-name-face :italic t))
+  "Face for italic text."
+  :group 'markdown-faces)
+
+(defface markdown-bold-face
+  '((t :inherit font-lock-variable-name-face :bold t))
+  "Face for bold text."
+  :group 'markdown-faces)
+
+(defface markdown-header-face
+  '((t :inherit font-lock-function-name-face :weight bold))
+  "Base face for headers."
+  :group 'markdown-faces)
+
+(defface markdown-header-face-1
+  '((t :inherit markdown-header-face))
+  "Face for level-1 headers."
+  :group 'markdown-faces)
+
+(defface markdown-header-face-2
+  '((t :inherit markdown-header-face))
+  "Face for level-2 headers."
+  :group 'markdown-faces)
+
+(defface markdown-header-face-3
+  '((t :inherit markdown-header-face))
+  "Face for level-3 headers."
+  :group 'markdown-faces)
+
+(defface markdown-header-face-4
+  '((t :inherit markdown-header-face))
+  "Face for level-4 headers."
+  :group 'markdown-faces)
+
+(defface markdown-header-face-5
+  '((t :inherit markdown-header-face))
+  "Face for level-5 headers."
+  :group 'markdown-faces)
+
+(defface markdown-header-face-6
+  '((t :inherit markdown-header-face))
+  "Face for level-6 headers."
+  :group 'markdown-faces)
+
+(defface markdown-inline-code-face
+  '((t :inherit font-lock-constant-face))
+  "Face for inline code."
+  :group 'markdown-faces)
+
+(defface markdown-list-face
+  '((t :inherit font-lock-builtin-face))
+  "Face for list item markers."
+  :group 'markdown-faces)
+
+(defface markdown-blockquote-face
+  '((t :inherit font-lock-doc-face))
+  "Face for blockquote sections."
+  :group 'markdown-faces)
+
+(defface markdown-pre-face
+  '((t :inherit font-lock-constant-face))
+  "Face for preformatted text."
+  :group 'markdown-faces)
+
+(defface markdown-link-face
+  '((t :inherit font-lock-keyword-face))
+  "Face for links."
+  :group 'markdown-faces)
+
+(defface markdown-reference-face
+  '((t :inherit font-lock-type-face))
+  "Face for link references."
+  :group 'markdown-faces)
+
+(defface markdown-url-face
+  '((t :inherit font-lock-string-face))
+  "Face for URLs."
+  :group 'markdown-faces)
+
+(defface markdown-link-title-face
+  '((t :inherit font-lock-comment-face))
+  "Face for reference link titles."
+  :group 'markdown-faces)
+
+(defface markdown-comment-face
+  '((t :inherit font-lock-comment-face))
+  "Face for HTML comments."
+  :group 'markdown-faces)
+
+(defface markdown-math-face
+  '((t :inherit font-lock-string-face))
+  "Face for LaTeX expressions."
+  :group 'markdown-faces)
+
+(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-1-atx
+  "^\\(# \\)\\(.*?\\)\\($\\| #+$\\)"
+  "Regular expression for level 1 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-2-atx
+  "^\\(## \\)\\(.*?\\)\\($\\| #+$\\)"
+  "Regular expression for level 2 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-3-atx
+  "^\\(### \\)\\(.*?\\)\\($\\| #+$\\)"
+  "Regular expression for level 3 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-4-atx
+  "^\\(#### \\)\\(.*?\\)\\($\\| #+$\\)"
+  "Regular expression for level 4 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-5-atx
+  "^\\(##### \\)\\(.*?\\)\\($\\| #+$\\)"
+  "Regular expression for level 5 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-6-atx
+  "^\\(###### \\)\\(.*?\\)\\($\\| #+$\\)"
+  "Regular expression for level 6 atx-style (hash mark) headers.")
+
+(defconst markdown-regex-header-1-setext
+  "^\\(.*\\)\n\\(===+\\)$"
+  "Regular expression for level 1 setext-style (underline) headers.")
+
+(defconst markdown-regex-header-2-setext
+  "^\\(.*\\)\n\\(---+\\)$"
+  "Regular expression for level 2 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
+  "^\\(    \\|\t\\).*$"
+  "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
+  (concat
+   "\\(" (mapconcat 'identity markdown-uri-types "\\|")
+   "\\):[^]\t\n\r<>,;() ]+")
+  "Regular expression for matching inline URIs.")
+
+(defconst markdown-regex-angle-uri
+  (concat
+   "\\(<\\)\\("
+   (mapconcat 'identity markdown-uri-types "\\|")
+   "\\):[^]\t\n\r<>,;()]+\\(>\\)")
+  "Regular expression for matching inline URIs in angle brackets.")
+
+(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-regex-list-indent
+  "^\\(\\s *\\)\\([0-9]+\\.\\|[\\*\\+-]\\)\\(\\s +\\)"
+  "Regular expression for matching indentation of list items.")
+
+; From html-helper-mode
+(defun markdown-match-comments (last)
+  "Matches HTML comments from the point to LAST"
+  (cond ((search-forward "<!--" last t)
+         (backward-char 4)
+         (let ((beg (point)))
+           (cond ((search-forward-regexp "--[ \t]*>" last t)
+                  (set-match-data (list beg (point)))
+                  t)
+                 (t nil))))
+        (t nil)))
+
+(defvar markdown-mode-font-lock-keywords-basic
+  (list
+   '(markdown-match-comments 0 markdown-comment-face t t)
+   (cons markdown-regex-code '(2 markdown-inline-code-face))
+   (cons markdown-regex-pre 'markdown-pre-face)
+   (cons markdown-regex-blockquote 'markdown-blockquote-face)
+   (cons markdown-regex-header-1-setext 'markdown-header-face-1)
+   (cons markdown-regex-header-2-setext 'markdown-header-face-2)
+   (cons markdown-regex-header-1-atx 'markdown-header-face-1)
+   (cons markdown-regex-header-2-atx 'markdown-header-face-2)
+   (cons markdown-regex-header-3-atx 'markdown-header-face-3)
+   (cons markdown-regex-header-4-atx 'markdown-header-face-4)
+   (cons markdown-regex-header-5-atx 'markdown-header-face-5)
+   (cons markdown-regex-header-6-atx 'markdown-header-face-6)
+   (cons markdown-regex-hr 'markdown-header-face)
+   (cons markdown-regex-list 'markdown-list-face)
+   (cons markdown-regex-link-inline
+         '((1 markdown-link-face t)
+           (2 markdown-url-face t)))
+   (cons markdown-regex-link-reference
+         '((1 markdown-link-face t)
+           (2 markdown-reference-face t)))
+   (cons markdown-regex-reference-definition
+         '((1 markdown-reference-face t)
+           (2 markdown-url-face t)
+           (3 markdown-link-title-face t)))
+   (cons markdown-regex-wiki-link 'markdown-link-face)
+   (cons markdown-regex-bold '(2 markdown-bold-face))
+   (cons markdown-regex-italic '(2 markdown-italic-face))
+   (cons markdown-regex-angle-uri 'markdown-link-face)
+   (cons markdown-regex-uri 'markdown-link-face)
+   (cons markdown-regex-email 'markdown-link-face)
+   )
+  "Syntax highlighting for Markdown files.")
+
+(defconst markdown-mode-font-lock-keywords-latex
+  (list
+   ;; Math mode $..$ or $$..$$
+   (cons markdown-regex-latex-expression '(2 markdown-math-face))
+   ;; Display mode equations with brackets: \[ \]
+   (cons markdown-regex-latex-display 'markdown-math-face)
+   ;; Equation reference (eq:foo)
+   (cons "(eq:\\w+)" 'markdown-reference-face)
+   ;; Equation reference \eqref{foo}
+   (cons "\\\\eqref{\\w+}" 'markdown-reference-face))
+  "Syntax highlighting for LaTeX fragments.")
+
+(defvar markdown-mode-font-lock-keywords
+  (append
+   (if markdown-enable-math
+       markdown-mode-font-lock-keywords-latex)
+   markdown-mode-font-lock-keywords-basic)
+  "Default highlighting expressions for Markdown mode.")
+
+
+
+;;; Syntax Table ==============================================================
+
+(defvar markdown-mode-syntax-table
+  (let ((markdown-mode-syntax-table (make-syntax-table)))
+    (modify-syntax-entry ?\" "w" markdown-mode-syntax-table)
+    markdown-mode-syntax-table)
+  "Syntax table for `markdown-mode'.")
+
+
+
+;;; Element Insertion =========================================================
+
+(defun markdown-wrap-or-insert (s1 s2)
+ "Insert the strings S1 and S2.
+If Transient Mark mode is on and a region is active, wrap the strings S1
+and S2 around the region."
+ (if (and transient-mark-mode mark-active)
+     (let ((a (region-beginning)) (b (region-end)))
+       (goto-char a)
+       (insert s1)
+       (goto-char (+ b (length s1)))
+       (insert s2))
+   (insert s1 s2)))
+
+(defun markdown-insert-hr ()
+  "Insert a horizonal rule."
+  (interactive)
+  (let (hr)
+    (dotimes (count (- markdown-hr-length 1) hr)        ; Count to n - 1
+      (setq hr (concat "* " hr)))                       ; Build HR string
+    (setq hr (concat hr "*\n"))                         ; Add the n-th *
+    (insert hr)))
+
+(defun markdown-insert-bold ()
+  "Insert markup for a bold word or phrase.
+If Transient Mark mode is on and a region is active, it is made bold."
+  (interactive)
+  (if markdown-bold-underscore
+      (markdown-wrap-or-insert "__" "__")
+    (markdown-wrap-or-insert "**" "**"))
+  (backward-char 2))
+
+(defun markdown-insert-italic ()
+  "Insert markup for an italic word or phrase.
+If Transient Mark mode is on and a region is active, it is made italic."
+  (interactive)
+  (if markdown-italic-underscore
+      (markdown-wrap-or-insert "_" "_")
+    (markdown-wrap-or-insert "*" "*"))
+  (backward-char 1))
+
+(defun markdown-insert-code ()
+  "Insert markup for an inline code fragment.
+If Transient Mark mode is on and a region is active, it is marked
+as inline code."
+  (interactive)
+  (markdown-wrap-or-insert "`" "`")
+  (backward-char 1))
+
+(defun markdown-insert-link ()
+  "Insert an inline link of the form []().
+If Transient Mark mode is on and a region is active, it is used
+as the link text."
+  (interactive)
+  (markdown-wrap-or-insert "[" "]")
+  (insert "()")
+  (backward-char 1))
+
+(defun markdown-insert-wiki-link ()
+  "Insert a wiki link of the form [[WikiLink]].
+If Transient Mark mode is on and a region is active, it is used
+as the link text."
+  (interactive)
+  (markdown-wrap-or-insert "[[" "]]")
+  (backward-char 2))
+
+(defun markdown-insert-image ()
+  "Insert an inline image tag of the form ![]().
+If Transient Mark mode is on and a region is active, it is used
+as the alt text of the image."
+  (interactive)
+  (markdown-wrap-or-insert "![" "]")
+  (insert "()")
+  (backward-char 1))
+
+(defun markdown-insert-header-1 ()
+  "Insert a first level atx-style (hash mark) header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+  (interactive)
+  (markdown-insert-header 1))
+
+(defun markdown-insert-header-2 ()
+  "Insert a second level atx-style (hash mark) header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+  (interactive)
+  (markdown-insert-header 2))
+
+(defun markdown-insert-header-3 ()
+  "Insert a third level atx-style (hash mark) header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+  (interactive)
+  (markdown-insert-header 3))
+
+(defun markdown-insert-header-4 ()
+  "Insert a fourth level atx-style (hash mark) header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+  (interactive)
+  (markdown-insert-header 4))
+
+(defun markdown-insert-header-5 ()
+  "Insert a fifth level atx-style (hash mark) header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+  (interactive)
+  (markdown-insert-header 5))
+
+(defun markdown-insert-header-6 ()
+  "Insert a sixth level atx-style (hash mark) header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+  (interactive)
+  (markdown-insert-header 6))
+
+(defun markdown-insert-header (n)
+  "Insert an atx-style (hash mark) header.
+With no prefix argument, insert a level-1 header.  With prefix N,
+insert a level-N header.  If Transient Mark mode is on and the
+region is active, it is used as the header text."
+  (interactive "p")
+  (unless n                             ; Test to see if n is defined
+    (setq n 1))                         ; Default to level 1 header
+  (let (hdr hdrl hdrr)
+    (dotimes (count n hdr)
+      (setq hdr (concat "#" hdr)))      ; Build a hash mark header string
+    (setq hdrl (concat hdr " "))
+    (setq hdrr (concat " " hdr))
+    (markdown-wrap-or-insert hdrl hdrr))
+  (backward-char (+ 1 n)))
+
+(defun markdown-insert-title ()
+  "Insert a setext-style (underline) first level header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+  (interactive)
+  (if (and transient-mark-mode mark-active)
+      (let ((a (region-beginning))
+            (b (region-end))
+            (len 0)
+            (hdr))
+        (setq len (- b a))
+        (dotimes (count len hdr)
+          (setq hdr (concat "=" hdr)))  ; Build a === title underline
+        (end-of-line)
+        (insert "\n" hdr "\n"))
+    (insert "\n==========\n")
+    (backward-char 12)))
+
+(defun markdown-insert-section ()
+  "Insert a setext-style (underline) second level header.
+If Transient Mark mode is on and a region is active, it is used
+as the header text."
+  (interactive)
+  (if (and transient-mark-mode mark-active)
+      (let ((a (region-beginning))
+            (b (region-end))
+            (len 0)
+            (hdr))
+        (setq len (- b a))
+        (dotimes (count len hdr)
+          (setq hdr (concat "-" hdr)))  ; Build a --- section underline
+        (end-of-line)
+        (insert "\n" hdr "\n"))
+    (insert "\n----------\n")
+    (backward-char 12)))
+
+(defun markdown-insert-blockquote ()
+  "Start a blockquote section (or blockquote the region).
+If Transient Mark mode is on and a region is active, it is used as
+the blockquote text."
+  (interactive)
+  (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
+      (markdown-blockquote-region (region-beginning) (region-end))
+    (insert "> ")))
+
+(defun markdown-block-region (beg end prefix)
+  "Format the region using a block prefix.
+Arguments BEG and END specify the beginning and end of the
+region.The characters PREFIX will appear at the beginning
+of each line."
+  (if mark-active
+      (save-excursion
+        (let ((endpos end))
+          ; Ensure that there is a leading blank line
+          (goto-char beg)
+          (while (not (looking-back "\n\n" 2))
+            (insert "\n")
+            (setq endpos (+ 1 endpos)))
+          ; Insert blockquote characters
+          (move-to-left-margin)
+          (while (< (point-at-bol) endpos)
+            (insert prefix)
+            (setq endpos (+ (length prefix) endpos))
+            (forward-line))
+          ; Move back before any blank lines at the end
+          (goto-char endpos)
+          (while (looking-back "\n" 1)
+            (backward-char))
+          ; Ensure one blank line at the end
+          (while (not (looking-at "\n\n"))
+            (insert "\n")
+            (backward-char))))))
+
+(defun markdown-blockquote-region (beg end)
+  "Blockquote the region.
+Arguments BEG and END specify the beginning and end of the region."
+  (interactive "*r")
+  (markdown-block-region beg end "> "))
+
+(defun markdown-insert-pre ()
+  "Start a preformatted section (or apply to the region).
+If Transient Mark mode is on and a region is active, it is marked
+as preformatted text."
+  (interactive)
+  (if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
+      (markdown-pre-region (region-beginning) (region-end))
+    (insert "    ")))
+
+(defun markdown-pre-region (beg end)
+  "Format the region as preformatted text.
+Arguments BEG and END specify the beginning and end of the region."
+  (interactive "*r")
+  (markdown-block-region beg end "    "))
+
+;;; Indentation ====================================================================
+
+;;; Indentation functions contributed by Bryan Kyle <bryan.kyle@gmail.com>..
+
+(defun markdown-indent-find-next-position (cur-pos positions)
+  "Return the position after the index of CUR-POS in POSITIONS."
+  (while (and positions
+              (not (equal cur-pos (car positions))))
+    (setq positions (cdr positions)))
+  (or (cadr positions) 0))
+
+(defun markdown-prev-line-indent-p ()
+  "Return t if the previous line is indented."
+  (save-excursion
+    (forward-line -1)
+    (goto-char (point-at-bol))
+    (if (re-search-forward "^\\s " (point-at-eol) t) t)))
+
+(defun markdown-prev-line-indent ()
+  "Return the number of leading whitespace characters in the previous line."
+  (save-excursion
+    (forward-line -1)
+    (goto-char (point-at-bol))
+    (when (re-search-forward "^\\s +" (point-at-eol) t)
+        (current-column))))
+
+(defun markdown-prev-list-indent ()
+  "Return position of the first non-list-marker on the previous line."
+  (save-excursion
+    (forward-line -1)
+    (goto-char (point-at-bol))
+    (when (re-search-forward markdown-regex-list-indent (point-at-eol) t)
+        (current-column))))
+
+(defun markdown-indent-line ()
+  "Indent the current line using some heuristics."
+  (interactive)
+  (if (markdown-prev-line-indent-p)
+      ;; If the current column is any of the positions, remove all
+      ;; of the positions up-to and including the current column
+      (indent-line-to
+       (markdown-indent-find-next-position
+        (current-column) (markdown-calc-indents)))))
+
+(defun markdown-calc-indents ()
+  "Return a list of indentation columns to cycle through."
+  (let (pos
+        prev-line-pos
+        positions
+        computed-pos)
+
+    ;; Previous line indent
+    (setq prev-line-pos (markdown-prev-line-indent))
+    (setq positions (cons prev-line-pos positions))
+
+    ;; Previous non-list-marker indent
+    (setq positions (cons (markdown-prev-list-indent) positions))
+
+    ;; Indentation of the previous line + tab-width
+    (cond
+     (prev-line-pos
+      (setq positions (cons (+ prev-line-pos tab-width) positions)))
+     (t
+      (setq positions (cons tab-width positions))))
+
+    ;; Indentation of the previous line - tab-width
+    (if (and prev-line-pos
+             (> prev-line-pos tab-width))
+        (setq positions (cons (- prev-line-pos tab-width) positions)))
+
+    ;; Indentation of preceeding list item
+    (setq pos
+          (save-excursion
+            (forward-line -1)
+            (catch 'break
+              (while (not (equal (point) (point-min)))
+                (forward-line -1)
+                (goto-char (point-at-bol))
+                (when (re-search-forward markdown-regex-list-indent (point-at-eol) t)
+                  (throw 'break (length (match-string 1)))))
+              nil)))
+    (if pos
+        (setq positions (cons pos positions)))
+
+    ;; First column
+    (setq positions (cons 0 (reverse positions)))
+
+    positions))
+
+(defun markdown-enter-key ()
+  "Insert a newline and optionally indent the next line."
+  (interactive)
+  (newline)
+  (if markdown-indent-on-enter
+      (funcall indent-line-function)))
+
+
+
+;;; Keymap ====================================================================
+
+(defvar markdown-mode-map
+  (let ((markdown-mode-map (make-keymap)))
+    ;; Element insertion
+    (define-key markdown-mode-map "\C-c\C-al" 'markdown-insert-link)
+    (define-key markdown-mode-map "\C-c\C-aw" 'markdown-insert-wiki-link)
+    (define-key markdown-mode-map "\C-c\C-ii" 'markdown-insert-image)
+    (define-key markdown-mode-map "\C-c\C-t1" 'markdown-insert-header-1)
+    (define-key markdown-mode-map "\C-c\C-t2" 'markdown-insert-header-2)
+    (define-key markdown-mode-map "\C-c\C-t3" 'markdown-insert-header-3)
+    (define-key markdown-mode-map "\C-c\C-t4" 'markdown-insert-header-4)
+    (define-key markdown-mode-map "\C-c\C-t5" 'markdown-insert-header-5)
+    (define-key markdown-mode-map "\C-c\C-t6" 'markdown-insert-header-6)
+    (define-key markdown-mode-map "\C-c\C-pb" 'markdown-insert-bold)
+    (define-key markdown-mode-map "\C-c\C-ss" 'markdown-insert-bold)
+    (define-key markdown-mode-map "\C-c\C-pi" 'markdown-insert-italic)
+    (define-key markdown-mode-map "\C-c\C-se" 'markdown-insert-italic)
+    (define-key markdown-mode-map "\C-c\C-pf" 'markdown-insert-code)
+    (define-key markdown-mode-map "\C-c\C-sc" 'markdown-insert-code)
+    (define-key markdown-mode-map "\C-c\C-sb" 'markdown-insert-blockquote)
+    (define-key markdown-mode-map "\C-c\C-s\C-b" 'markdown-blockquote-region)
+    (define-key markdown-mode-map "\C-c\C-sp" 'markdown-insert-pre)
+    (define-key markdown-mode-map "\C-c\C-s\C-p" 'markdown-pre-region)
+    (define-key markdown-mode-map "\C-c-" 'markdown-insert-hr)
+    (define-key markdown-mode-map "\C-c\C-tt" 'markdown-insert-title)
+    (define-key markdown-mode-map "\C-c\C-ts" 'markdown-insert-section)
+	;; Indentation
+	(define-key markdown-mode-map "\C-m" 'markdown-enter-key)
+    ;; Visibility cycling
+    (define-key markdown-mode-map (kbd "<tab>") 'markdown-cycle)
+    (define-key markdown-mode-map (kbd "<S-iso-lefttab>") 'markdown-shifttab)
+    ;; Markdown functions
+    (define-key markdown-mode-map "\C-c\C-cm" 'markdown)
+    (define-key markdown-mode-map "\C-c\C-cp" 'markdown-preview)
+    ;; References
+    (define-key markdown-mode-map "\C-c\C-cc" 'markdown-check-refs)
+    markdown-mode-map)
+  "Keymap for Markdown major mode.")
+
+;;; Menu ==================================================================
+
+(easy-menu-define markdown-mode-menu markdown-mode-map
+  "Menu for Markdown mode"
+  '("Markdown"
+    ("Show/Hide"
+     ["Cycle visibility" markdown-cycle (outline-on-heading-p)]
+     ["Cycle global visibility" markdown-shifttab])
+    "---"
+    ["Compile" markdown]
+    ["Preview" markdown-preview]
+    "---"
+    ("Headers (setext)"
+     ["Insert Title" markdown-insert-title]
+     ["Insert Section" markdown-insert-section])
+    ("Headers (atx)"
+     ["First level" markdown-insert-header-1]
+     ["Second level" markdown-insert-header-2]
+     ["Third level" markdown-insert-header-3]
+     ["Fourth level" markdown-insert-header-4]
+     ["Fifth level" markdown-insert-header-5]
+     ["Sixth level" markdown-insert-header-6])
+    "---"
+    ["Bold" markdown-insert-bold]
+    ["Italic" markdown-insert-italic]
+    ["Blockquote" markdown-insert-blockquote]
+    ["Preformatted" markdown-insert-pre]
+    ["Code" markdown-insert-code]
+    "---"
+    ["Insert inline link" markdown-insert-link]
+    ["Insert image" markdown-insert-image]
+    ["Insert horizontal rule" markdown-insert-hr]
+    "---"
+    ["Check references" markdown-check-refs]
+    "---"
+    ["Version" markdown-show-version]
+    ))
+
+
+
+;;; References ================================================================
+
+;;; Undefined reference checking code by Dmitry Dzhus <mail@sphinx.net.ru>.
+
+(defconst markdown-refcheck-buffer
+  "*Undefined references for %BUFFER%*"
+  "Pattern for name of buffer for listing undefined references.
+The string %BUFFER% will be replaced by the corresponding
+`markdown-mode' buffer name.")
+
+(defun markdown-has-reference-definition (reference)
+    "Find out whether Markdown REFERENCE is defined.
+
+REFERENCE should include the square brackets, like [this]."
+    (let ((reference (downcase reference)))
+      (save-excursion
+        (goto-char (point-min))
+        (catch 'found
+          (while (re-search-forward markdown-regex-reference-definition nil t)
+            (when (string= reference (downcase (match-string-no-properties 1)))
+              (throw 'found t)))))))
+
+(defun markdown-get-undefined-refs ()
+  "Return a list of undefined Markdown references.
+
+Result is an alist of pairs (reference . occurencies), where
+occurencies is itself another alist of pairs (label .
+line-number).
+
+For example, an alist corresponding to [Nice editor][Emacs] at line 12,
+\[GNU Emacs][Emacs] at line 45 and [manual][elisp] at line 127 is
+\((\"[emacs]\" (\"[Nice editor]\" . 12) (\"[GNU Emacs]\" . 45)) (\"[elisp]\" (\"[manual]\" . 127)))."
+  (let ((missing))
+    (save-excursion
+      (goto-char (point-min))
+      (while
+          (re-search-forward markdown-regex-link-reference nil t)
+        (let* ((label (match-string-no-properties 1))
+               (reference (match-string-no-properties 2))
+               (target (downcase (if (string= reference "[]") label reference))))
+          (unless (markdown-has-reference-definition target)
+            (let ((entry (assoc target missing)))
+              (if (not entry)
+                  (add-to-list 'missing (cons target
+                                              (list (cons label (markdown-line-number-at-pos)))) t)
+                (setcdr entry
+                        (append (cdr entry) (list (cons label (markdown-line-number-at-pos))))))))))
+      missing)))
+
+(defun markdown-add-missing-ref-definition (ref buffer &optional recheck)
+  "Add blank REF definition to the end of BUFFER.
+
+REF is a Markdown reference in square brackets, like \"[lisp-history]\".
+
+When RECHECK is non-nil, BUFFER gets rechecked for undefined
+references so that REF disappears from the list of those links."
+  (with-current-buffer buffer
+      (when (not (eq major-mode 'markdown-mode))
+        (error "Not available in current mode"))
+      (goto-char (point-max))
+      (indent-new-comment-line)
+      (insert (concat ref ": ")))
+  (switch-to-buffer-other-window buffer)
+  (goto-char (point-max))
+  (when recheck
+    (markdown-check-refs t)))
+
+;; Button which adds an empty Markdown reference definition to the end
+;; of buffer specified as its 'target-buffer property. Reference name
+;; is button's label
+(when (>= emacs-major-version 22)
+  (define-button-type 'markdown-ref-button
+    'help-echo "Push to create an empty reference definition"
+    'face 'bold
+    'action (lambda (b)
+              (markdown-add-missing-ref-definition
+               (button-label b) (button-get b 'target-buffer) t))))
+
+;; Button jumping to line in buffer specified as its 'target-buffer
+;; property. Line number is button's 'line property.
+(when (>= emacs-major-version 22)
+  (define-button-type 'goto-line-button
+    'help-echo "Push to go to this line"
+    'face 'italic
+    'action (lambda (b)
+              (message (button-get b 'buffer))
+              (switch-to-buffer-other-window (button-get b 'target-buffer))
+              (goto-line (button-get b 'target-line)))))
+
+(defun markdown-check-refs (&optional silent)
+  "Show all undefined Markdown references in current `markdown-mode' buffer.
+
+If SILENT is non-nil, do not message anything when no undefined
+references found.
+
+Links which have empty reference definitions are considered to be
+defined."
+  (interactive "P")
+  (when (not (eq major-mode 'markdown-mode))
+    (error "Not available in current mode"))
+  (let ((oldbuf (current-buffer))
+        (refs (markdown-get-undefined-refs))
+        (refbuf (get-buffer-create (replace-regexp-in-string
+                                 "%BUFFER%" (buffer-name)
+                                 markdown-refcheck-buffer t))))
+    (if (null refs)
+        (progn
+          (when (not silent)
+            (message "No undefined references found"))
+          (kill-buffer refbuf))
+      (with-current-buffer refbuf
+        (when view-mode
+          (View-exit-and-edit))
+        (erase-buffer)
+        (insert "Following references lack definitions:")
+        (newline 2)
+        (dolist (ref refs)
+          (let ((button-label (format "%s" (car ref))))
+            (if (>= emacs-major-version 22)
+                ;; Create a reference button in Emacs 22
+                (insert-text-button button-label
+                                    :type 'markdown-ref-button
+                                    'target-buffer oldbuf)
+              ;; Insert reference as text in Emacs < 22
+              (insert button-label)))
+          (insert " (")
+          (dolist (occurency (cdr ref))
+            (let ((line (cdr occurency)))
+              (if (>= emacs-major-version 22)
+                  ;; Create a line number button in Emacs 22
+                  (insert-button (number-to-string line)
+                                 :type 'goto-line-button
+                                 'target-buffer oldbuf
+                                 'target-line line)
+                ;; Insert line number as text in Emacs < 22
+                (insert (number-to-string line)))
+              (insert " "))) (delete-backward-char 1)
+          (insert ")")
+          (newline))
+        (view-buffer-other-window refbuf)
+        (goto-line 4)))))
+
+
+;;; Outline ===================================================================
+
+;; The following visibility cycling code was taken from org-mode
+;; by Carsten Dominik and adapted for markdown-mode.
+
+(defvar markdown-cycle-global-status 1)
+(defvar markdown-cycle-subtree-status nil)
+
+;; Based on org-end-of-subtree from org.el
+(defun markdown-end-of-subtree (&optional invisible-OK)
+  "Move to the end of the current subtree.
+Only visible heading lines are considered, unless INVISIBLE-OK is
+non-nil."
+  (outline-back-to-heading invisible-OK)
+  (let ((first t)
+        (level (funcall outline-level)))
+    (while (and (not (eobp))
+                (or first (> (funcall outline-level) level)))
+      (setq first nil)
+      (outline-next-heading))
+    (if (memq (preceding-char) '(?\n ?\^M))
+        (progn
+          ;; Go to end of line before heading
+          (forward-char -1)
+          (if (memq (preceding-char) '(?\n ?\^M))
+              ;; leave blank line before heading
+              (forward-char -1)))))
+  (point))
+
+;; Based on org-cycle from org.el.
+(defun markdown-cycle (&optional arg)
+  "Visibility cycling for Markdown mode.
+If ARG is t, perform global visibility cycling.  If the point is
+at an atx-style header, cycle visibility of the corresponding
+subtree.  Otherwise, insert a tab using `indent-relative'."
+  (interactive "P")
+  (cond
+     ((eq arg t) ;; Global cycling
+      (cond
+       ((and (eq last-command this-command)
+             (eq markdown-cycle-global-status 2))
+        ;; Move from overview to contents
+        (hide-sublevels 1)
+        (message "CONTENTS")
+        (setq markdown-cycle-global-status 3))
+
+       ((and (eq last-command this-command)
+             (eq markdown-cycle-global-status 3))
+        ;; Move from contents to all
+        (show-all)
+        (message "SHOW ALL")
+        (setq markdown-cycle-global-status 1))
+
+       (t
+        ;; Defaults to overview
+        (hide-body)
+        (message "OVERVIEW")
+        (setq markdown-cycle-global-status 2))))
+
+     ((save-excursion (beginning-of-line 1) (looking-at outline-regexp))
+      ;; At a heading: rotate between three different views
+      (outline-back-to-heading)
+      (let ((goal-column 0) eoh eol eos)
+        ;; Determine boundaries
+        (save-excursion
+          (outline-back-to-heading)
+          (save-excursion
+            (beginning-of-line 2)
+            (while (and (not (eobp)) ;; this is like `next-line'
+                        (get-char-property (1- (point)) 'invisible))
+              (beginning-of-line 2)) (setq eol (point)))
+          (outline-end-of-heading)   (setq eoh (point))
+          (markdown-end-of-subtree t)
+          (skip-chars-forward " \t\n")
+          (beginning-of-line 1) ; in case this is an item
+          (setq eos (1- (point))))
+        ;; Find out what to do next and set `this-command'
+      (cond
+         ((= eos eoh)
+          ;; Nothing is hidden behind this heading
+          (message "EMPTY ENTRY")
+          (setq markdown-cycle-subtree-status nil))
+         ((>= eol eos)
+          ;; Entire subtree is hidden in one line: open it
+          (show-entry)
+          (show-children)
+          (message "CHILDREN")
+          (setq markdown-cycle-subtree-status 'children))
+         ((and (eq last-command this-command)
+               (eq markdown-cycle-subtree-status 'children))
+          ;; We just showed the children, now show everything.
+          (show-subtree)
+          (message "SUBTREE")
+          (setq markdown-cycle-subtree-status 'subtree))
+         (t
+          ;; Default action: hide the subtree.
+          (hide-subtree)
+          (message "FOLDED")
+          (setq markdown-cycle-subtree-status 'folded)))))
+
+     (t
+      (message "TAB")
+      (funcall indent-line-function))))
+
+;; Based on org-shifttab from org.el.
+(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)
+  (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))
+  (let (title)
+    (setq title (buffer-name))
+    (save-excursion
+      (set-buffer "*markdown-output*")
+      (goto-char (point-min))
+      (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 markdown-css-path
+          (insert "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\""
+                  markdown-css-path
+                  "\"  />\n"))
+      (insert "</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*"))
+
+
+;;; 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."
+  (let ((opoint (or pos (point))) start)
+    (save-excursion
+      (goto-char (point-min))
+      (setq start (point))
+      (goto-char opoint)
+      (forward-line 0)
+      (1+ (count-lines start (point))))))
+
+(defun markdown-nobreak-p ()
+  "Returns nil if it is ok for fill-paragraph to insert a line
+  break at point"
+  ;; are we inside in square brackets
+  (looking-back "\\[[^]]*"))
+
+
+
+;;; Mode definition  ==========================================================
+
+(defun markdown-show-version ()
+  "Show the version number in the minibuffer."
+  (interactive)
+  (message "markdown-mode, version %s" markdown-mode-version))
+
+;;;###autoload
+(define-derived-mode markdown-mode text-mode "Markdown"
+  "Major mode for editing Markdown files."
+  ;; Comments
+  (make-local-variable 'comment-start)
+  (setq comment-start "<!-- ")
+  (make-local-variable 'comment-end)
+  (setq comment-end " -->")
+  (make-local-variable 'comment-start-skip)
+  (setq comment-start-skip "<!--[ \t]*")
+  (make-local-variable 'comment-column)
+  (setq comment-column 0)
+  ;; Font lock.
+  (set (make-local-variable 'font-lock-defaults)
+       '(markdown-mode-font-lock-keywords))
+  (set (make-local-variable 'font-lock-multiline) t)
+  ;; For menu support in XEmacs
+  (easy-menu-add markdown-mode-menu markdown-mode-map)
+  ;; Make filling work with lists (unordered, ordered, and definition)
+  (set (make-local-variable 'paragraph-start)
+       "\f\\|[ \t]*$\\|^[ \t]*[*+-] \\|^[ \t*][0-9]+\\.\\|^[ \t]*: ")
+  ;; Outline mode
+  (make-local-variable 'outline-regexp)
+  (setq outline-regexp "#+")
+  ;; Cause use of ellipses for invisible text.
+  (add-to-invisibility-spec '(outline . t))
+  ;; Indentation and filling
+  (make-local-variable 'fill-nobreak-predicate)
+  (add-hook 'fill-nobreak-predicate 'markdown-nobreak-p)
+  (setq indent-line-function markdown-indent-function))
+
+;(add-to-list 'auto-mode-alist '("\\.text$" . markdown-mode))
+
+(provide 'markdown-mode)
+
+;;; markdown-mode.el ends here