1. Yaron Minsky
  2. js-elisp

Commits

Stephen Weeks  committed 213832c

added lots of external elisp: edit-server, filladapt, markdown-mode, ocamlspot, smooth-scrolling, tuareg

  • Participants
  • Parent commits 6d1d482
  • Branches default

Comments (0)

Files changed (30)

File elisp/contrib/edit-server.el

View file
+;;; edit-server.el --- server that responds to edit requests from Chrome
+
+;; Copyright (C) 2009-2011  Alex Bennee
+;; Copyright (C) 2010-2011  Riccardo Murri
+
+;; Author: Alex Bennee <alex@bennee.com>
+;; Maintainer: Alex Bennee <alex@bennee.com>
+;; Version: 1.10
+;; Homepage: https://github.com/stsquad/emacs_chrome
+
+;; This file is not part of GNU Emacs.
+
+;; This file 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 3, or (at your option)
+;; any later version.
+
+;; This file 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, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This provides an edit server to respond to requests from the Chrome
+;; Emacs Chrome plugin. This is my first attempt at doing something
+;; with sockets in Emacs. I based it on the following examples:
+;;
+;;   http://www.emacswiki.org/emacs/EmacsEchoServer
+;;   http://nullprogram.com/blog/2009/05/17/
+;;
+;; To use it ensure the file is in your load-path and add something
+;; like the following examples to your .emacs:
+;;
+;; To open pages for editing in new buffers in your existing Emacs
+;; instance:
+;;
+;;   (when (require 'edit-server nil t)
+;;     (setq edit-server-new-frame nil)
+;;     (edit-server-start))
+;;
+;; To open pages for editing in new frames using a running emacs
+;; started in --daemon mode:
+;;
+;;   (when (and (require 'edit-server nil t) (daemonp))
+;;     (edit-server-start))
+;;
+;; Buffers are edited in `text-mode' by default; to use a different
+;; major mode, change `edit-server-default-major-mode' or customize
+;; `edit-server-url-major-mode-alist' to specify major modes based
+;; on the remote URL:
+;;
+;;   (setq edit-server-url-major-mode-alist
+;;         '(("github\\.com" . markdown-mode)))
+;;
+;; Alternatively, set the mode in `edit-server-start-hook'.  For
+;; example:
+;;
+;; (add-hook 'edit-server-start-hook
+;;           (lambda ()
+;;             (when (string-match "github.com" (buffer-name))
+;; 	      (markdown-mode))))
+
+
+;;; Code:
+
+;; uncomment to debug
+;; (setq debug-on-error t)
+;; (setq edebug-all-defs t)
+
+(unless (featurep 'make-network-process)
+  (error "Incompatible version of [X]Emacs - lacks make-network-process"))
+
+;;; Customization
+
+(defcustom edit-server-port 9292
+  "Local port the edit server listens to."
+  :group 'edit-server
+  :type 'integer)
+
+(defcustom edit-server-host nil
+  "If not nil, accept connections from HOST address rather than just
+localhost. This may present a security issue."
+  :group 'edit-server
+  :type 'boolean)
+
+(defcustom edit-server-verbose nil
+  "If not nil, log connections and progress also to the echo area."
+  :group 'edit-server
+  :type 'boolean)
+
+(defcustom edit-server-done-hook nil
+  "Hook run when done editing a buffer for the Emacs HTTP edit-server.
+Current buffer holds the text that is about to be sent back to the client."
+  :group 'edit-server
+  :type 'hook)
+
+(defcustom edit-server-start-hook nil
+  "Hook run when starting a editing buffer.  Current buffer is
+the fully prepared editing buffer.  Use this hook to enable
+buffer-specific modes or add key bindings."
+  :group 'edit-server
+  :type 'hook)
+
+;; frame options
+
+(defcustom edit-server-new-frame t
+  "If not nil, edit each buffer in a new frame (and raise it)."
+  :group 'edit-server
+  :type 'boolean)
+
+(defcustom edit-server-new-frame-alist
+  '((name . "Emacs TEXTAREA")
+    (width . 80)
+    (height . 25)
+    (minibuffer . t)
+    (menu-bar-lines . t))
+  "Frame parameters for new frames.  See `default-frame-alist' for examples.
+If nil, the new frame will use the existing `default-frame-alist' values."
+  :group 'edit-server
+  :type '(repeat (cons :format "%v"
+		       (symbol :tag "Parameter")
+		       (sexp :tag "Value"))))
+
+(defcustom edit-server-default-major-mode
+  'text-mode
+  "The default major mode to use in editing buffers, if no other
+mode is selected by `edit-server-url-major-mode-alist'."
+  :group 'edit-server
+  :type 'function)
+
+(defcustom edit-server-url-major-mode-alist
+  nil
+  "A-list of patterns and corresponding functions; when the first
+pattern is encountered which matches `edit-server-url', the
+corresponding function will be called in order to set the desired
+major mode. If no pattern matches,
+`edit-server-default-major-mode' will be used."
+  :group 'edit-server
+  :type '(alist :key-type (string :tag "Regexp")
+		:value-type (function :tag "Major mode function")))
+
+(defcustom edit-server-new-frame-mode-line t
+  "Show the emacs frame's mode-line if set to t; hide if nil."
+  :group 'edit-server
+  :type 'boolean)
+
+;;; Variables
+
+(defconst edit-server-process-buffer-name " *edit-server*"
+  "Template name of the edit-server process buffers.")
+
+(defconst edit-server-log-buffer-name "*edit-server-log*"
+  "Template name of the edit-server process buffers.")
+
+(defconst edit-server-edit-buffer-name "TEXTAREA"
+  "Template name of the edit-server text editing buffers.")
+
+(defvar edit-server-clients ()
+  "List of all client processes associated with the server process.")
+
+;; Buffer local variables
+;;
+;; These are all required to associate the edit buffer with the
+;; correct connection to the client and allow for the buffer to be sent
+;; back when ready. They are `permanent-local` to avoid being reset if
+;; the buffer changes major modes.
+
+(defvar edit-server-proc nil
+  "Network process associated with the current edit.")
+(make-variable-buffer-local 'edit-server-proc)
+(put 'edit-server-proc 'permanent-local t)
+
+(defvar edit-server-frame nil
+  "The frame created for a new edit-server process.")
+(make-variable-buffer-local 'edit-server-frame)
+(put 'edit-server-frame 'permanent-local t)
+
+(defvar edit-server-phase nil
+  "Symbol indicating the state of the HTTP request parsing.")
+(make-variable-buffer-local 'edit-server-phase)
+(put 'edit-server-phase 'permanent-local t)
+
+(defvar edit-server-received nil
+  "Number of bytes received so far in the client buffer.
+Depending on the character encoding, may be different from the buffer length.")
+(make-variable-buffer-local 'edit-server-received)
+(put 'edit-server-received 'permanent-local t)
+
+(defvar edit-server-request nil
+  "The HTTP request (GET, HEAD, POST) received.")
+(make-variable-buffer-local 'edit-server-request)
+(put 'edit-server-request 'permanent-local t)
+
+(defvar edit-server-content-length nil
+  "The value gotten from the HTTP `Content-Length' header.")
+(make-variable-buffer-local 'edit-server-content-length)
+(put 'edit-server-content-length 'permanent-local t)
+
+(defvar edit-server-url nil
+  "The value gotten from the HTTP `x-url' header.")
+(make-variable-buffer-local 'edit-server-url)
+(put 'edit-server-url 'permanent-local t)
+
+;;; Mode magic
+;;
+;; We want to re-map some of the keys to trigger edit-server-done
+;; instead of the usual emacs like behaviour. However using
+;; local-set-key will affect all buffers of the same mode, hence we
+;; define a special (derived) mode for handling editing of text areas.
+
+
+(defvar edit-server-edit-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "C-x C-s") 'edit-server-save)
+    (define-key map (kbd "C-x #")   'edit-server-done)
+    (define-key map (kbd "C-c C-c") 'edit-server-done)
+    (define-key map (kbd "C-x C-c") 'edit-server-done)
+    map)
+  "Keymap for minor mode `edit-server-edit-mode'.
+
+Redefine a few common Emacs keystrokes to functions that can
+deal with the response to the edit-server request.
+
+Any of the following keys will close the buffer and send the text
+to the HTTP client: C-x #, C-c C-c.
+
+Pressing C-x C-s will save the current state to the kill-ring.
+
+If any of the above isused with a prefix argument, the
+unmodified text is sent back instead.")
+
+(define-minor-mode edit-server-edit-mode
+  "Minor mode enabled on buffers opened by `edit-server-accept'.
+
+Its sole purpose is currently to enable
+`edit-server-edit-mode-map', which overrides common keystrokes to
+send a response back to the client."
+  :group 'edit-server
+  :lighter " EditSrv"
+  :init-value nil
+  :keymap edit-server-edit-mode-map)
+
+
+;; Edit Server socket code
+
+(defun edit-server-start (&optional verbose)
+  "Start the edit server.
+
+If argument VERBOSE is non-nil, logs all server activity to buffer
+`*edit-server-log*'.  When called interactivity, a prefix argument
+will cause it to be verbose."
+  (interactive "P")
+  (if (or (process-status "edit-server")
+	  (null (condition-case err
+		    (make-network-process
+		     :name "edit-server"
+		     :buffer edit-server-process-buffer-name
+		     :family 'ipv4
+		     :host (or edit-server-host 'local)
+		     :service edit-server-port
+		     :log 'edit-server-accept
+		     :server t
+		     :noquery t)
+		  (file-error nil))))
+      (message "An edit-server process is already running")
+    (setq edit-server-clients '())
+    (if verbose (get-buffer-create edit-server-log-buffer-name))
+    (edit-server-log nil "Created a new edit-server process")))
+
+(defun edit-server-stop nil
+  "Stop the edit server"
+  (interactive)
+  (while edit-server-clients
+    (edit-server-kill-client (car edit-server-clients))
+    (setq edit-server-clients (cdr edit-server-clients)))
+  (if (process-status "edit-server")
+      (delete-process "edit-server")
+    (message "No edit server running"))
+  (when (get-buffer edit-server-process-buffer-name)
+    (kill-buffer edit-server-process-buffer-name)))
+
+(defun edit-server-log (proc fmt &rest args)
+  "If a `*edit-server-log*' buffer exists, write STRING to it.
+This is done for logging purposes.  If `edit-server-verbose' is
+non-nil, then STRING is also echoed to the message line."
+  (let ((string (apply 'format fmt args)))
+    (if edit-server-verbose
+	(message string))
+    (if (get-buffer edit-server-log-buffer-name)
+	(with-current-buffer edit-server-log-buffer-name
+	  (goto-char (point-max))
+	  (insert (current-time-string)
+		  " "
+		  (if (processp proc)
+		      (concat
+		       (buffer-name (process-buffer proc))
+		       ": ")
+		    "") ; nil is not acceptable to 'insert
+		  string)
+	  (or (bolp) (newline))))))
+
+(defun edit-server-accept (server client msg)
+  "Accept a new client connection."
+  (let ((buffer (generate-new-buffer edit-server-process-buffer-name)))
+    (when (fboundp 'set-buffer-multibyte)
+      (set-buffer-multibyte t)) ; djb
+    (buffer-disable-undo buffer)
+    (set-process-buffer client buffer)
+    (set-process-filter client 'edit-server-filter)
+    ;; kill-buffer kills the associated process
+    (set-process-query-on-exit-flag client nil)
+    (with-current-buffer buffer
+      (setq edit-server-phase 'wait
+	    edit-server-received 0
+	    edit-server-request nil))
+    (setq edit-server-content-length nil
+	  edit-server-url nil))
+  (add-to-list 'edit-server-clients client)
+  (edit-server-log client msg))
+
+(defun edit-server-filter (proc string)
+  "Process data received from the client."
+  ;; there is no guarantee that data belonging to the same client
+  ;; request will arrive all in one go; therefore, we must accumulate
+  ;; data in the buffer and process it in different phases, which
+  ;; requires us to keep track of the processing state.
+  (with-current-buffer (process-buffer proc)
+    (insert string)
+    (setq edit-server-received
+	  (+ edit-server-received (string-bytes string)))
+    (when (eq edit-server-phase 'wait)
+      ;; look for a complete HTTP request string
+      (save-excursion
+	(goto-char (point-min))
+	(when (re-search-forward
+	       "^\\([A-Z]+\\)\\s-+\\(\\S-+\\)\\s-+\\(HTTP/[0-9\.]+\\)\r?\n"
+	       nil t)
+	  (edit-server-log
+	   proc "Got HTTP `%s' request, processing in buffer `%s'..."
+	   (match-string 1) (current-buffer))
+	  (setq edit-server-request (match-string 1))
+	  (setq edit-server-content-length nil)
+	  (setq edit-server-phase 'head))))
+
+    (when (eq edit-server-phase 'head)
+      ;; look for "Content-length" header
+      (save-excursion
+	(goto-char (point-min))
+	(when (re-search-forward "^Content-Length:\\s-+\\([0-9]+\\)" nil t)
+	  (setq edit-server-content-length
+		(string-to-number (match-string 1)))))
+      ;; look for "x-url" header
+      (save-excursion
+	(goto-char (point-min))
+	(when (re-search-forward "^x-url: .*//\\(.*\\)/" nil t)
+	  (setq edit-server-url (match-string 1))))
+      ;; look for head/body separator
+      (save-excursion
+	(goto-char (point-min))
+	(when (re-search-forward "\\(\r?\n\\)\\{2\\}" nil t)
+	  ;; HTTP headers are pure ASCII (1 char = 1 byte), so we can subtract
+	  ;; the buffer position from the count of received bytes
+	  (setq edit-server-received
+		(- edit-server-received (- (match-end 0) (point-min))))
+	  ;; discard headers - keep only HTTP content in buffer
+	  (delete-region (point-min) (match-end 0))
+	  (setq edit-server-phase 'body))))
+
+    (when (eq edit-server-phase 'body)
+      (if (and edit-server-content-length
+	       (> edit-server-content-length edit-server-received))
+	  (edit-server-log proc
+			   "Received %d bytes of %d ..."
+			   edit-server-received edit-server-content-length)
+	;; all content transferred - process request now
+	(cond
+	 ((string= edit-server-request "POST")
+	  ;; create editing buffer, and move content to it
+	  (edit-server-create-edit-buffer proc))
+	 (t
+	  ;; send 200 OK response to any other request
+	  (edit-server-send-response proc "edit-server is running.\n" t)))
+	;; wait for another connection to arrive
+	(setq edit-server-received 0)
+	(setq edit-server-phase 'wait)))))
+
+(defun edit-server-create-frame(buffer)
+  "Create a frame for the edit server"
+  (if edit-server-new-frame
+      (let ((new-frame
+	     (if (memq window-system '(ns mac))
+		 ;; Aquamacs, Emacs NS, Emacs (experimental) Mac port
+		 (make-frame edit-server-new-frame-alist)
+	       (make-frame-on-display (getenv "DISPLAY")
+				      edit-server-new-frame-alist))))
+	(unless edit-server-new-frame-mode-line
+	  (setq mode-line-format nil))
+	(select-frame new-frame)
+	(when (and (eq window-system 'x)
+		   (fboundp 'x-send-client-message))
+	  (x-send-client-message nil 0 nil
+				 "_NET_ACTIVE_WINDOW" 32
+				 '(1 0 0)))
+	(raise-frame new-frame)
+	(set-window-buffer (frame-selected-window new-frame) buffer)
+	new-frame)
+    (pop-to-buffer buffer)
+    (raise-frame)
+    nil))
+
+(defun edit-server-choose-major-mode ()
+  "Use `edit-server-url-major-mode-alist' to choose a major mode
+initialization function based on `edit-server-url', or fall back
+to `edit-server-default-major-mode'"
+  (let ((pairs edit-server-url-major-mode-alist)
+	(mode edit-server-default-major-mode))
+    (while pairs
+      (let ((entry (car pairs)))
+	(if (string-match (car entry) edit-server-url)
+	    (setq mode (cdr entry)
+		  pairs nil)
+	  (setq pairs (cdr pairs)))))
+    (funcall mode)))
+
+(defun edit-server-create-edit-buffer(proc)
+  "Create an edit buffer, place content in it and save the network
+	process for the final call back"
+  (let ((buffer (generate-new-buffer
+		 (or edit-server-url
+		     edit-server-edit-buffer-name))))
+    (with-current-buffer buffer
+      (when (fboundp 'set-buffer-multibyte)
+	(set-buffer-multibyte t))) ; djb
+    (copy-to-buffer buffer (point-min) (point-max))
+    (with-current-buffer buffer
+      (edit-server-choose-major-mode)
+      ;; Allow `edit-server-start-hook' to override the major mode.
+      ;; (re)setting the minor mode seems to clear the buffer-local
+      ;; variables that we depend upon for the response, so call the
+      ;; hooks early on
+      (run-hooks 'edit-server-start-hook)
+      (not-modified)
+      (add-hook 'kill-buffer-hook 'edit-server-abort* nil t)
+      (buffer-enable-undo)
+      (setq edit-server-proc proc
+	    edit-server-frame (edit-server-create-frame buffer))
+      (edit-server-edit-mode))))
+
+(defun edit-server-send-response (proc &optional body close)
+  "Send an HTTP 200 OK response back to process PROC.
+Optional second argument BODY specifies the response content:
+    - If nil, the HTTP response will have null content.
+    - If a string, the string is sent as response content.
+    - Any other value will cause the contents of the current
+      buffer to be sent.
+If optional third argument CLOSE is non-nil, then process PROC
+and its buffer are killed with `edit-server-kill-client'."
+  (interactive)
+  (if (processp proc)
+      (let ((response-header (concat
+			      "HTTP/1.0 200 OK\n"
+			      (format "Server: Emacs/%s\n" emacs-version)
+			      "Date: "
+			      (format-time-string
+			       "%a, %d %b %Y %H:%M:%S GMT\n"
+			       (current-time)))))
+	(process-send-string proc response-header)
+	(process-send-string proc "\n")
+	(cond
+	 ((stringp body)
+	  (process-send-string proc (encode-coding-string body 'utf-8)))
+	 ((not body) nil)
+	 (t
+	  (encode-coding-region (point-min) (point-max) 'utf-8)
+	  (process-send-region proc (point-min) (point-max))))
+	(process-send-eof proc)
+	(when close
+	  (edit-server-kill-client proc))
+	(edit-server-log proc "Editing done, sent HTTP OK response."))
+    (message "edit-server-send-response: invalid proc (bug?)")))
+
+(defun edit-server-kill-client (proc)
+  "Kill client process PROC and remove it from the list."
+  (let ((procbuf (process-buffer proc)))
+    (delete-process proc)
+    (kill-buffer procbuf)
+    (setq edit-server-clients (delq proc edit-server-clients))))
+
+(defun edit-server-done (&optional abort nokill)
+  "Finish editing: send HTTP response back, close client and editing buffers.
+
+The current contents of the buffer are sent back to the HTTP
+client, unless argument ABORT is non-nil, in which case then the
+original text is sent back.
+If optional second argument NOKILL is non-nil, then the editing
+buffer is not killed.
+
+When called interactively, use prefix arg to abort editing."
+  (interactive "P")
+  ;; Do nothing if the connection is closed by the browser (tab killed, etc.)
+  (unless (eq (process-status edit-server-proc) 'closed)
+    (let ((buffer (current-buffer))
+	  (proc edit-server-proc)
+	  (procbuf (process-buffer edit-server-proc)))
+      ;; edit-server-* vars are buffer-local,
+      ;; so they must be used before issuing kill-buffer
+      (if abort
+	  ;; send back original content
+	  (with-current-buffer procbuf
+	    (run-hooks 'edit-server-done-hook)
+	    (edit-server-send-response proc t))
+	;; send back edited content
+	(save-restriction
+	  (widen)
+	  (buffer-disable-undo)
+	  ;; ensure any format encoding is done (like longlines)
+	  (dolist (format buffer-file-format)
+	    (format-encode-region (point-min) (point-max) format))
+	  ;; send back
+	  (run-hooks 'edit-server-done-hook)
+	  (edit-server-send-response edit-server-proc t)
+	  ;; restore formats (only useful if we keep the buffer)
+	  (dolist (format buffer-file-format)
+	    (format-decode-region (point-min) (point-max) format))
+	  (buffer-enable-undo)))
+      (when edit-server-frame
+	(delete-frame edit-server-frame))
+      ;; delete-frame may change the current buffer
+      (unless nokill
+	(kill-buffer buffer))
+      (edit-server-kill-client proc))))
+
+;;
+;; There are a couple of options for handling the save
+;; action. The intent is to preserve data but not finish
+;; editing. There are a couple of approaches that could
+;; be taken:
+;;  a) Use the iterative edit-server option (send a buffer
+;;     back to the client which then returns new request
+;;     to continue the session).
+;;  b) Back-up the edit session to a file
+;;  c) Save the current buffer to the kill-ring
+;;
+;; I've attempted to do a) a couple of times but I keep running
+;; into problems which I think are emacs bugs. So for now I'll
+;; just push the current buffer to the kill-ring.
+
+(defun edit-server-save ()
+  "Save the current state of the edit buffer."
+  (interactive)
+  (save-restriction
+    (widen)
+    (buffer-disable-undo)
+    (copy-region-as-kill (point-min) (point-max))
+    (buffer-enable-undo)))
+
+(defun edit-server-abort ()
+  "Discard editing and send the original text back to the browser."
+  (interactive)
+  (edit-server-done t))
+
+(defun edit-server-abort* ()
+  "Discard editing and send the original text back to the browser,
+but don't kill the editing buffer."
+  (interactive)
+  (edit-server-done t t))
+
+(provide 'edit-server)
+
+;;; edit-server.el ends here

File elisp/contrib/filladapt.el

View file
+;;; Adaptive fill
+;;; Copyright (C) 1989, 1995-1998 Kyle E. Jones
+;;;
+;;; 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.
+;;;
+;;; A copy of the GNU General Public License can be obtained from this
+;;; program's author (send electronic mail to kyle@uunet.uu.net) or from
+;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+;;; 02139, USA.
+;;;
+;;; Send bug reports to kyle_jones@wonderworks.com
+
+;; LCD Archive Entry:
+;; filladapt|Kyle Jones|kyle_jones@wonderworks.com|
+;; Minor mode to adaptively set fill-prefix and overload filling functions|
+;; 28-February-1998|2.12|~/packages/filladapt.el|
+
+;; These functions enhance the default behavior of Emacs' Auto Fill
+;; mode and the commands fill-paragraph, lisp-fill-paragraph,
+;; fill-region-as-paragraph and fill-region.
+;;
+;; The chief improvement is that the beginning of a line to be
+;; filled is examined and, based on information gathered, an
+;; appropriate value for fill-prefix is constructed.  Also the
+;; boundaries of the current paragraph are located.  This occurs
+;; only if the fill prefix is not already non-nil.
+;;
+;; The net result of this is that blurbs of text that are offset
+;; from left margin by asterisks, dashes, and/or spaces, numbered
+;; examples, included text from USENET news articles, etc. are
+;; generally filled correctly with no fuss.
+;;
+;; Since this package replaces existing Emacs functions, it cannot
+;; be autoloaded.  Save this in a file named filladapt.el in a
+;; Lisp directory that Emacs knows about, byte-compile it and put
+;;    (require 'filladapt)
+;; in your .emacs file.
+;;
+;; Note that in this release Filladapt mode is a minor mode and it is
+;; _off_ by default.  If you want it to be on by default, use
+;;   (setq-default filladapt-mode t)
+;;
+;; M-x filladapt-mode toggles Filladapt mode on/off in the current
+;; buffer.
+;;
+;; Use
+;;     (add-hook 'text-mode-hook 'turn-on-filladapt-mode)
+;; to have Filladapt always enabled in Text mode.
+;;
+;; Use
+;;     (add-hook 'c-mode-hook 'turn-off-filladapt-mode)
+;; to have Filladapt always disabled in C mode.
+;;
+;; In many cases, you can extend Filladapt by adding appropriate
+;; entries to the following three `defvar's.  See `postscript-comment'
+;; or `texinfo-comment' as a sample of what needs to be done.
+;;
+;;     filladapt-token-table
+;;     filladapt-token-match-table
+;;     filladapt-token-conversion-table
+
+(and (featurep 'filladapt)
+     (error "filladapt cannot be loaded twice in the same Emacs session."))
+
+(provide 'filladapt)
+
+(defvar filladapt-version "2.12"
+  "Version string for filladapt.")
+
+;; BLOB to make custom stuff work even without customize
+;; 2012-04-26 sweeks: Craig says we don't need the following.  And it causes annoying
+;; warnings about "old-style backquotes" to be shown to the user.  So, I commented it
+;; out.
+;;
+;; (eval-and-compile
+;;   (condition-case ()
+;;       (require 'custom)
+;;     (error nil))
+;;   (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
+;;       nil ;; We've got what we needed
+;;     ;; We have the old custom-library, hack around it!
+;;     (defmacro defgroup (&rest args)
+;;       nil)
+;;     (defmacro defcustom (var value doc &rest args)
+;;       (` (defvar (, var) (, value) (, doc))))))
+
+(defgroup filladapt nil
+  "Enhanced filling"
+  :group 'fill)
+
+(defvar filladapt-mode nil
+  "Non-nil means that Filladapt minor mode is enabled.
+Use the filladapt-mode command to toggle the mode on/off.")
+(make-variable-buffer-local 'filladapt-mode)
+
+(defcustom filladapt-mode-line-string " Filladapt"
+  "*String to display in the modeline when Filladapt mode is active.
+Set this to nil if you don't want a modeline indicator for Filladapt."
+  :type 'string
+  :group 'filladapt)
+
+(defcustom filladapt-fill-column-tolerance nil
+  "*Tolerate filled paragraph lines ending this far from the fill column.
+If any lines other than the last paragraph line end at a column
+less than fill-column - filladapt-fill-column-tolerance, fill-column will
+be adjusted using the filladapt-fill-column-*-fuzz variables and
+the paragraph will be re-filled until the tolerance is achieved
+or filladapt runs out of fuzz values to try.
+
+A nil value means behave normally, that is, don't try refilling
+paragraphs to make filled line lengths fit within any particular
+range."
+  :type '(choice (const nil)
+		 integer)
+  :group 'filladapt)
+
+(defcustom filladapt-fill-column-forward-fuzz 5
+  "*Try values from fill-column to fill-column plus this variable
+when trying to make filled paragraph lines fall with the tolerance
+range specified by filladapt-fill-column-tolerance."
+  :type 'integer
+  :group 'filladapt)
+
+(defcustom filladapt-fill-column-backward-fuzz 5
+  "*Try values from fill-column to fill-column minus this variable
+when trying to make filled paragraph lines fall with the tolerance
+range specified by filladapt-fill-column-tolerance."
+  :type 'integer
+  :group 'filladapt)
+
+;; install on minor-mode-alist
+(or (assq 'filladapt-mode minor-mode-alist)
+    (setq minor-mode-alist (cons (list 'filladapt-mode
+				       'filladapt-mode-line-string)
+				 minor-mode-alist)))
+
+(defcustom filladapt-token-table
+  '(
+    ;; this must be first
+    ("^" beginning-of-line)
+    ;; Included text in news or mail replies
+    (">+" citation->)
+    ;; Included text generated by SUPERCITE.  We can't hope to match all
+    ;; the possible variations, your mileage may vary.
+    ("\\(\\w\\|[0-9]\\)[^'`\"< \t\n]*>[ \t]*" supercite-citation)
+    ;; Lisp comments
+    (";+" lisp-comment)
+    ;; UNIX shell comments
+    ("#+" sh-comment)
+    ;; Postscript comments
+    ("%+" postscript-comment)
+    ;; C++ comments
+    ("///*" c++-comment)
+    ;; Texinfo comments
+    ("@c[ \t]" texinfo-comment)
+    ("@comment[ \t]" texinfo-comment)
+    ;; Bullet types.
+    ;;
+    ;; LaTex \item
+    ;;
+    ("\\\\item[ \t]" bullet)
+    ;;
+    ;; 1. xxxxx
+    ;;    xxxxx
+    ;;
+    ("[0-9]+\\.[ \t]" bullet)
+    ;;
+    ;; 2.1.3  xxxxx xx x xx x
+    ;;        xxx
+    ;;
+    ("[0-9]+\\(\\.[0-9]+\\)+[ \t]" bullet)
+    ;;
+    ;; a. xxxxxx xx
+    ;;    xxx xxx
+    ;;
+    ("[A-Za-z]\\.[ \t]" bullet)
+    ;;
+    ;; 1) xxxx x xx x xx   or   (1) xx xx x x xx xx
+    ;;    xx xx xxxx                xxx xx x x xx x
+    ;;
+    ("(?[0-9]+)[ \t]" bullet)
+    ;;
+    ;; a) xxxx x xx x xx   or   (a) xx xx x x xx xx
+    ;;    xx xx xxxx                xxx xx x x xx x
+    ;;
+    ("(?[A-Za-z])[ \t]" bullet)
+    ;;
+    ;; 2a. xx x xxx x x xxx
+    ;;     xxx xx x xx x
+    ;;
+    ("[0-9]+[A-Za-z]\\.[ \t]" bullet)
+    ;;
+    ;; 1a) xxxx x xx x xx   or   (1a) xx xx x x xx xx
+    ;;     xx xx xxxx                 xxx xx x x xx x
+    ;;
+    ("(?[0-9]+[A-Za-z])[ \t]" bullet)
+    ;;
+    ;; -  xx xxx xxxx   or   *  xx xx x xxx xxx
+    ;;    xxx xx xx             x xxx x xx x x x
+    ;;
+    ("[-~*+]+[ \t]" bullet)
+    ;;
+    ;; o  xx xxx xxxx xx x xx xxx x xxx xx x xxx
+    ;;    xxx xx xx
+    ;;
+    ("o[ \t]" bullet)
+    ;; don't touch
+    ("[ \t]+" space)
+    ("$" end-of-line)
+   )
+  "Table of tokens filladapt knows about.
+Format is
+
+   ((REGEXP SYM) ...)
+
+filladapt uses this table to build a tokenized representation of
+the beginning of the current line.  Each REGEXP is matched
+against the beginning of the line until a match is found.
+Matching is done case-sensitively.  The corresponding SYM is
+added to the list, point is moved to (match-end 0) and the
+process is repeated.  The process ends when there is no REGEXP in
+the table that matches what is at point."
+  :type '(repeat (list regexp symbol))
+  :group 'filladapt)
+
+(defcustom filladapt-not-token-table
+  '(
+    "[Ee]\\.g\\.[ \t,]"
+    "[Ii]\\.e\\.[ \t,]"
+    ;; end-of-line isn't a token if whole line is empty
+    "^$"
+   )
+  "List of regexps that can never be a token.
+Before trying the regular expressions in filladapt-token-table,
+the regexps in this list are tried.  If any regexp in this list
+matches what is at point then the token generator gives up and
+doesn't try any of the regexps in filladapt-token-table.
+
+Regexp matching is done case-sensitively."
+  :type '(repeat regexp)
+  :group 'filladapt)
+
+(defcustom filladapt-token-match-table
+  '(
+    (citation-> citation->)
+    (supercite-citation supercite-citation)
+    (lisp-comment lisp-comment)
+    (sh-comment sh-comment)
+    (postscript-comment postscript-comment)
+    (c++-comment c++-comment)
+    (texinfo-comment texinfo-comment)
+    (bullet)
+    (space bullet space)
+    (beginning-of-line beginning-of-line)
+   )
+  "Table describing what tokens a certain token will match.
+
+To decide whether a line belongs in the current paragraph,
+filladapt creates a token list for the fill prefix of both lines.
+Tokens and the columns where tokens end are compared.  This table
+specifies what a certain token will match.
+
+Table format is
+
+   (SYM [SYM1 [SYM2 ...]])
+
+The first symbol SYM is the token, subsequent symbols are the
+tokens that SYM will match."
+  :type '(repeat (repeat symbol))
+  :group 'filladapt)
+
+(defcustom filladapt-token-match-many-table
+  '(
+    space
+   )
+  "List of tokens that can match multiple tokens.
+If one of these tokens appears in a token list, it will eat all
+matching tokens in a token list being matched against it until it
+encounters a token that doesn't match or a token that ends on
+a greater column number."
+  :type '(repeat symbol)
+  :group 'filladapt)
+
+(defcustom filladapt-token-paragraph-start-table
+  '(
+    bullet
+   )
+  "List of tokens that indicate the start of a paragraph.
+If parsing a line generates a token list containing one of
+these tokens, then the line is considered to be the start of a
+paragraph."
+  :type '(repeat symbol)
+  :group 'filladapt)
+
+(defcustom filladapt-token-conversion-table
+  '(
+    (citation-> . exact)
+    (supercite-citation . exact)
+    (lisp-comment . exact)
+    (sh-comment . exact)
+    (postscript-comment . exact)
+    (c++-comment . exact)
+    (texinfo-comment . exact)
+    (bullet . spaces)
+    (space . exact)
+    (end-of-line . exact)
+   )
+  "Table that specifies how to convert a token into a fill prefix.
+Table format is
+
+   ((SYM . HOWTO) ...)
+
+SYM is the symbol naming the token to be converted.
+HOWTO specifies how to do the conversion.
+  `exact' means copy the token's string directly into the fill prefix.
+  `spaces' means convert all characters in the token string that are
+      not a TAB or a space into spaces and copy the resulting string into
+      the fill prefix."
+  :type '(repeat (cons symbol (choice (const exact)
+				      (const spaces))))
+  :group 'filladapt)
+
+(defvar filladapt-function-table
+  (let ((assoc-list
+	 (list (cons 'fill-paragraph (symbol-function 'fill-paragraph))
+	       (cons 'fill-region (symbol-function 'fill-region))
+	       (cons 'fill-region-as-paragraph
+		     (symbol-function 'fill-region-as-paragraph))
+	       (cons 'do-auto-fill (symbol-function 'do-auto-fill)))))
+    ;; v18 Emacs doesn't have lisp-fill-paragraph
+    (if (fboundp 'lisp-fill-paragraph)
+	(nconc assoc-list
+	       (list (cons 'lisp-fill-paragraph
+			   (symbol-function 'lisp-fill-paragraph)))))
+    assoc-list )
+  "Table containing the old function definitions that filladapt usurps.")
+
+(defcustom filladapt-fill-paragraph-post-hook nil
+  "Hooks run after filladapt runs fill-paragraph."
+  :type 'hook
+  :group 'filladapt)
+
+(defvar filladapt-inside-filladapt nil
+  "Non-nil if the filladapt version of a fill function executing.
+Currently this is only checked by the filladapt version of
+fill-region-as-paragraph to avoid this infinite recursion:
+
+  fill-region-as-paragraph -> fill-paragraph -> fill-region-as-paragraph ...")
+
+(defcustom filladapt-debug nil
+  "Non-nil means filladapt debugging is enabled.
+Use the filladapt-debug command to turn on debugging.
+
+With debugging enabled, filladapt will
+
+    a. display the proposed indentation with the tokens highlighted
+       using filladapt-debug-indentation-face-1 and
+       filladapt-debug-indentation-face-2.
+    b. display the current paragraph using the face specified by
+       filladapt-debug-paragraph-face."
+  :type 'boolean
+  :group 'filladapt)
+
+(if filladapt-debug
+    (add-hook 'post-command-hook 'filladapt-display-debug-info-maybe))
+
+(defvar filladapt-debug-indentation-face-1 'highlight
+  "Face used to display the indentation when debugging is enabled.")
+
+(defvar filladapt-debug-indentation-face-2 'secondary-selection
+  "Another face used to display the indentation when debugging is enabled.")
+
+(defvar filladapt-debug-paragraph-face 'bold
+  "Face used to display the current paragraph when debugging is enabled.")
+
+(defvar filladapt-debug-indentation-extents nil)
+(make-variable-buffer-local 'filladapt-debug-indentation-extents)
+(defvar filladapt-debug-paragraph-extent nil)
+(make-variable-buffer-local 'filladapt-debug-paragraph-extent)
+
+;; kludge city, see references in code.
+(defvar filladapt-old-line-prefix)
+
+(defun do-auto-fill ()
+  (catch 'done
+    (if (and filladapt-mode (null fill-prefix))
+	(save-restriction
+	  (let ((paragraph-ignore-fill-prefix nil)
+		;; if the user wanted this stuff, they probably
+		;; wouldn't be using filladapt-mode.
+		(adaptive-fill-mode nil)
+		(adaptive-fill-regexp nil)
+		;; need this or Emacs 19 ignores fill-prefix when
+		;; inside a comment.
+		(comment-multi-line t)
+		(filladapt-inside-filladapt t)
+		fill-prefix retval)
+	    (if (filladapt-adapt nil nil)
+		(progn
+		  (setq retval (filladapt-funcall 'do-auto-fill))
+		  (throw 'done retval))))))
+    (filladapt-funcall 'do-auto-fill)))
+
+(defun filladapt-fill-paragraph (function arg)
+  (catch 'done
+    (if (and filladapt-mode (null fill-prefix))
+	(save-restriction
+	  (let ((paragraph-ignore-fill-prefix nil)
+		;; if the user wanted this stuff, they probably
+		;; wouldn't be using filladapt-mode.
+		(adaptive-fill-mode nil)
+		(adaptive-fill-regexp nil)
+		;; need this or Emacs 19 ignores fill-prefix when
+		;; inside a comment.
+		(comment-multi-line t)
+		fill-prefix retval)
+	    (if (filladapt-adapt t nil)
+		(progn
+		  (if filladapt-fill-column-tolerance
+		      (let* ((low (- fill-column
+				     filladapt-fill-column-backward-fuzz))
+			     (high (+ fill-column
+				      filladapt-fill-column-forward-fuzz))
+			     (old-fill-column fill-column)
+			     (fill-column fill-column)
+			     (lim (- high low))
+			     (done nil)
+			     (sign 1)
+			     (delta 0))
+			(while (not done)
+			  (setq retval (filladapt-funcall function arg))
+			  (if (filladapt-paragraph-within-fill-tolerance)
+			      (setq done 'success)
+			    (setq delta (1+ delta)
+				  sign (* sign -1)
+				  fill-column (+ fill-column (* delta sign)))
+			    (while (and (<= delta lim)
+					(or (< fill-column low)
+					    (> fill-column high)))
+			      (setq delta (1+ delta)
+				    sign (* sign -1)
+				    fill-column (+ fill-column
+						   (* delta sign))))
+			    (setq done (> delta lim))))
+			;; if the paragraph lines never fell
+			;; within the tolerances, refill using
+			;; the old fill-column.
+			(if (not (eq done 'success))
+			    (let ((fill-column old-fill-column))
+			      (setq retval (filladapt-funcall function arg)))))
+		    (setq retval (filladapt-funcall function arg)))
+		  (run-hooks 'filladapt-fill-paragraph-post-hook)
+		  (throw 'done retval))))))
+    ;; filladapt-adapt failed, so do fill-paragraph normally.
+    (filladapt-funcall function arg)))
+
+(defun fill-paragraph (arg)
+  "Fill paragraph at or after point.  Prefix arg means justify as well.
+
+(This function has been overloaded with the `filladapt' version.)
+
+If `sentence-end-double-space' is non-nil, then period followed by one
+space does not end a sentence, so don't break a line there.
+
+If `fill-paragraph-function' is non-nil, we call it (passing our
+argument to it), and if it returns non-nil, we simply return its value."
+  (interactive "*P")
+  (let ((filladapt-inside-filladapt t))
+    (filladapt-fill-paragraph 'fill-paragraph arg)))
+
+(defun lisp-fill-paragraph (&optional arg)
+  "Like \\[fill-paragraph], but handle Emacs Lisp comments.
+
+(This function has been overloaded with the `filladapt' version.)
+
+If any of the current line is a comment, fill the comment or the
+paragraph of it that point is in, preserving the comment's indentation
+and initial semicolons."
+  (interactive "*P")
+  (let ((filladapt-inside-filladapt t))
+    (filladapt-fill-paragraph 'lisp-fill-paragraph arg)))
+
+(defun fill-region-as-paragraph (beg end &optional justify
+				 nosqueeze squeeze-after)
+  "Fill the region as one paragraph.
+
+(This function has been overloaded with the `filladapt' version.)
+
+It removes any paragraph breaks in the region and extra newlines at the end,
+indents and fills lines between the margins given by the
+`current-left-margin' and `current-fill-column' functions.
+It leaves point at the beginning of the line following the paragraph.
+
+Normally performs justification according to the `current-justification'
+function, but with a prefix arg, does full justification instead.
+
+From a program, optional third arg JUSTIFY can specify any type of
+justification.  Fourth arg NOSQUEEZE non-nil means not to make spaces
+between words canonical before filling.  Fifth arg SQUEEZE-AFTER, if non-nil,
+means don't canonicalize spaces before that position.
+
+If `sentence-end-double-space' is non-nil, then period followed by one
+space does not end a sentence, so don't break a line there."
+  (interactive "*r\nP")
+  (if (and filladapt-mode (not filladapt-inside-filladapt))
+      (save-restriction
+	(narrow-to-region beg end)
+	(let ((filladapt-inside-filladapt t)
+	      line-start last-token)
+	  (goto-char beg)
+	  (while (equal (char-after (point)) ?\n)
+	    (delete-char 1))
+	  (end-of-line)
+	  (while (zerop (forward-line))
+	    (if (setq last-token
+		      (car (filladapt-tail (filladapt-parse-prefixes))))
+		(progn
+		  (setq line-start (point))
+		  (move-to-column (nth 1 last-token))
+		  (delete-region line-start (point))))
+	    ;; Dance...
+	    ;;
+	    ;; Do this instead of (delete-char -1) to keep
+	    ;; markers on the correct side of the whitespace.
+	    (goto-char (1- (point)))
+	    (insert " ")
+	    (delete-char 1)
+
+	    (end-of-line))
+	  (goto-char beg)
+	  (fill-paragraph justify))
+	;; In XEmacs 19.12 and Emacs 18.59 fill-region relies on
+	;; fill-region-as-paragraph to do this.  If we don't do
+	;; it, fill-region will spin in an endless loop.
+	(goto-char (point-max)))
+    (condition-case nil
+	;; five args for Emacs 19.31
+	(filladapt-funcall 'fill-region-as-paragraph beg end
+			   justify nosqueeze squeeze-after)
+      (wrong-number-of-arguments
+       (condition-case nil
+	   ;; four args for Emacs 19.29
+	   (filladapt-funcall 'fill-region-as-paragraph beg end
+			      justify nosqueeze)
+	 ;; three args for the rest of the world.
+	 (wrong-number-of-arguments
+	  (filladapt-funcall 'fill-region-as-paragraph beg end justify)))))))
+
+(defun fill-region (beg end &optional justify nosqueeze to-eop)
+  "Fill each of the paragraphs in the region.
+
+(This function has been overloaded with the `filladapt' version.)
+
+Prefix arg (non-nil third arg, if called from program) means justify as well.
+
+Noninteractively, fourth arg NOSQUEEZE non-nil means to leave
+whitespace other than line breaks untouched, and fifth arg TO-EOP
+non-nil means to keep filling to the end of the paragraph (or next
+hard newline, if `use-hard-newlines' is on).
+
+If `sentence-end-double-space' is non-nil, then period followed by one
+space does not end a sentence, so don't break a line there."
+  (interactive "*r\nP")
+  (if (and filladapt-mode (not filladapt-inside-filladapt))
+      (save-restriction
+	(narrow-to-region beg end)
+	(let ((filladapt-inside-filladapt t)
+	      start)
+	  (goto-char beg)
+	  (while (not (eobp))
+	    (setq start (point))
+	    (while (and (not (eobp)) (not (filladapt-parse-prefixes)))
+	      (forward-line 1))
+	    (if (not (equal start (point)))
+		(progn
+		  (save-restriction
+		    (narrow-to-region start (point))
+		    (fill-region start (point) justify nosqueeze to-eop)
+		    (goto-char (point-max)))
+		  (if (and (not (bolp)) (not (eobp)))
+		      (forward-line 1))))
+	    (if (filladapt-parse-prefixes)
+		(progn
+		  (save-restriction
+		    ;; for the clipping region
+		    (filladapt-adapt t t)
+		    (fill-paragraph justify)
+		    (goto-char (point-max)))
+		  (if (and (not (bolp)) (not (eobp)))
+		      (forward-line 1)))))))
+    (condition-case nil
+	(filladapt-funcall 'fill-region beg end justify nosqueeze to-eop)
+      (wrong-number-of-arguments
+       (condition-case nil
+	   (filladapt-funcall 'fill-region beg end justify nosqueeze)
+	 (wrong-number-of-arguments
+	  (filladapt-funcall 'fill-region beg end justify)))))))
+
+(defvar zmacs-region-stays) ; for XEmacs
+
+(defun filladapt-mode (&optional arg)
+  "Toggle Filladapt minor mode.
+With arg, turn Filladapt mode on iff arg is positive.  When
+Filladapt mode is enabled, auto-fill-mode and the fill-paragraph
+command are both smarter about guessing a proper fill-prefix and
+finding paragraph boundaries when bulleted and indented lines and
+paragraphs are used."
+  (interactive "P")
+  ;; don't deactivate the region.
+  (setq zmacs-region-stays t)
+  (setq filladapt-mode (or (and arg (> (prefix-numeric-value arg) 0))
+			   (and (null arg) (null filladapt-mode))))
+  (if (fboundp 'force-mode-line-update)
+      (force-mode-line-update)
+    (set-buffer-modified-p (buffer-modified-p))))
+
+(defun turn-on-filladapt-mode ()
+  "Unconditionally turn on Filladapt mode in the current buffer."
+  (filladapt-mode 1))
+
+(defun turn-off-filladapt-mode ()
+  "Unconditionally turn off Filladapt mode in the current buffer."
+  (filladapt-mode -1))
+
+(defun filladapt-funcall (function &rest args)
+  "Call the old definition of a function that filladapt has usurped."
+  (apply (cdr (assoc function filladapt-function-table)) args))
+
+(defun filladapt-paragraph-start (list)
+  "Returns non-nil if LIST contains a paragraph starting token.
+LIST should be a token list as returned by filladapt-parse-prefixes."
+  (catch 'done
+    (while list
+      (if (memq (car (car list)) filladapt-token-paragraph-start-table)
+	  (throw 'done t))
+      (setq list (cdr list)))))
+
+(defun filladapt-parse-prefixes ()
+  "Parse all the tokens after point and return a list of them.
+The tokens regular expressions are specified in
+filladapt-token-table.  The list returned is of this form
+
+  ((SYM COL STRING) ...)
+
+SYM is a token symbol as found in filladapt-token-table.
+COL is the column at which the token ended.
+STRING is the token's text."
+  (save-excursion
+    (let ((token-list nil)
+	  (done nil)
+	  (old-point (point))
+	  (case-fold-search nil)
+	  token-table not-token-table moved)
+      (catch 'done
+	(while (not done)
+	  (setq not-token-table filladapt-not-token-table)
+	  (while not-token-table
+	    (if (looking-at (car not-token-table))
+		(throw 'done t))
+	    (setq not-token-table (cdr not-token-table)))
+	  (setq token-table filladapt-token-table
+		done t)
+	  (while token-table
+	    (if (null (looking-at (car (car token-table))))
+		(setq token-table (cdr token-table))
+	      (goto-char (match-end 0))
+	      (setq token-list (cons (list (nth 1 (car token-table))
+					   (current-column)
+					   (buffer-substring
+					    (match-beginning 0)
+					    (match-end 0)))
+				     token-list)
+		    moved (not (eq (point) old-point))
+		    token-table (if moved nil (cdr token-table))
+		    done (not moved)
+		    old-point (point))))))
+      (nreverse token-list))))
+
+(defun filladapt-tokens-match-p (list1 list2)
+  "Compare two token lists and return non-nil if they match, nil otherwise.
+The lists are walked through in lockstep, comparing tokens.
+
+When two tokens A and B are compared, they are considered to
+match if
+
+    1. A appears in B's list of matching tokens or
+       B appears in A's list of matching tokens
+and
+    2. A and B both end at the same column
+         or
+       A can match multiple tokens and ends at a column > than B
+         or
+       B can match multiple tokens and ends at a column > than A
+
+In the case where the end columns differ the list pointer for the
+token with the greater end column is not moved forward, which
+allows its current token to be matched against the next token in
+the other list in the next iteration of the matching loop.
+
+All tokens must be matched in order for the lists to be considered
+matching."
+  (let ((matched t)
+	(done nil))
+    (while (and (not done) list1 list2)
+      (let* ((token1 (car (car list1)))
+	     (token1-matches-many-p
+	         (memq token1 filladapt-token-match-many-table))
+	     (token1-matches (cdr (assq token1 filladapt-token-match-table)))
+	     (token1-endcol (nth 1 (car list1)))
+	     (token2 (car (car list2)))
+	     (token2-matches-many-p
+	         (memq token2 filladapt-token-match-many-table))
+	     (token2-matches (cdr (assq token2 filladapt-token-match-table)))
+	     (token2-endcol (nth 1 (car list2)))
+	     (tokens-match (or (memq token1 token2-matches)
+			       (memq token2 token1-matches))))
+	(cond ((not tokens-match)
+	       (setq matched nil
+		     done t))
+	      ((and token1-matches-many-p token2-matches-many-p)
+	       (cond ((= token1-endcol token2-endcol)
+		      (setq list1 (cdr list1)
+			    list2 (cdr list2)))
+		     ((< token1-endcol token2-endcol)
+		      (setq list1 (cdr list1)))
+		     (t
+		      (setq list2 (cdr list2)))))
+	      (token1-matches-many-p
+	       (cond ((= token1-endcol token2-endcol)
+		      (setq list1 (cdr list1)
+			    list2 (cdr list2)))
+		     ((< token1-endcol token2-endcol)
+		      (setq matched nil
+			    done t))
+		     (t
+		      (setq list2 (cdr list2)))))
+	      (token2-matches-many-p
+	       (cond ((= token1-endcol token2-endcol)
+		      (setq list1 (cdr list1)
+			    list2 (cdr list2)))
+		     ((< token2-endcol token1-endcol)
+		      (setq matched nil
+			    done t))
+		     (t
+		      (setq list1 (cdr list1)))))
+	      ((= token1-endcol token2-endcol)
+	       (setq list1 (cdr list1)
+		     list2 (cdr list2)))
+	      (t
+	       (setq matched nil
+		     done t)))))
+    (and matched (null list1) (null list2)) ))
+
+(defun filladapt-make-fill-prefix (list)
+  "Build a fill-prefix for a token LIST.
+filladapt-token-conversion-table specifies how this is done."
+  (let ((prefix-list nil)
+	(conversion-spec nil))
+    (while list
+      (setq conversion-spec (cdr (assq (car (car list))
+				       filladapt-token-conversion-table)))
+      (cond ((eq conversion-spec 'spaces)
+	     (setq prefix-list
+		   (cons
+		    (filladapt-convert-to-spaces (nth 2 (car list)))
+		    prefix-list)))
+	    ((eq conversion-spec 'exact)
+	     (setq prefix-list
+		   (cons
+		    (nth 2 (car list))
+		    prefix-list))))
+      (setq list (cdr list)))
+    (apply (function concat) (nreverse prefix-list)) ))
+
+(defun filladapt-paragraph-within-fill-tolerance ()
+  (catch 'done
+    (save-excursion
+      (let ((low (- fill-column filladapt-fill-column-tolerance))
+	    (shortline nil))
+	(goto-char (point-min))
+	(while (not (eobp))
+	  (if shortline
+	      (throw 'done nil)
+	    (end-of-line)
+	    (setq shortline (< (current-column) low))
+	    (forward-line 1)))
+	t ))))
+
+(defun filladapt-convert-to-spaces (string)
+  "Return a copy of STRING, with all non-tabs and non-space changed to spaces."
+  (let ((i 0)
+	(space-list '(?\  ?\t))
+	(space ?\ )
+	(lim (length string)))
+    (setq string (copy-sequence string))
+    (while (< i lim)
+      (if (not (memq (aref string i) space-list))
+	  (aset string i space))
+      (setq i (1+ i)))
+    string ))
+
+(defun filladapt-adapt (paragraph debugging)
+  "Set fill-prefix based on the contents of the current line.
+
+If the first arg PARAGRAPH is non-nil, also set a clipping region
+around the current paragraph.
+
+If the second arg DEBUGGING is non-nil, don't do the kludge that's
+necessary to make certain paragraph fills work properly."
+  (save-excursion
+    (beginning-of-line)
+    (let ((token-list (filladapt-parse-prefixes))
+	  curr-list done)
+      (if (null token-list)
+	  nil
+	(setq fill-prefix (filladapt-make-fill-prefix token-list))
+	(if paragraph
+	    (let (beg end)
+	      (if (filladapt-paragraph-start token-list)
+		  (setq beg (point))
+		(save-excursion
+		  (setq done nil)
+		  (while (not done)
+		    (cond ((not (= 0 (forward-line -1)))
+			   (setq done t
+				 beg (point)))
+			  ((not (filladapt-tokens-match-p
+				 token-list
+				 (setq curr-list (filladapt-parse-prefixes))))
+			   (forward-line 1)
+			   (setq done t
+				 beg (point)))
+			  ((filladapt-paragraph-start curr-list)
+			   (setq done t
+				 beg (point)))))))
+	      (save-excursion
+		(setq done nil)
+		(while (not done)
+		  (cond ((not (= 0 (progn (end-of-line) (forward-line 1))))
+			 (setq done t
+			       end (point)))
+			((not (filladapt-tokens-match-p
+			       token-list
+			       (setq curr-list (filladapt-parse-prefixes))))
+			 (setq done t
+			       end (point)))
+			((filladapt-paragraph-start curr-list)
+			 (setq done t
+			       end (point))))))
+	      (narrow-to-region beg end)
+	      ;; Multiple spaces after the bullet at the start of
+	      ;; a hanging list paragraph get squashed by
+	      ;; fill-paragraph.  We kludge around this by
+	      ;; replacing the line prefix with the fill-prefix
+	      ;; used by the rest of the lines in the paragraph.
+	      ;; fill-paragraph will not alter the fill prefix so
+	      ;; we win.  The post hook restores the old line prefix
+	      ;; after fill-paragraph has been called.
+	      (if (and paragraph (not debugging))
+		  (let (col)
+		    (setq col (nth 1 (car (filladapt-tail token-list))))
+		    (goto-char (point-min))
+		    (move-to-column col)
+		    (setq filladapt-old-line-prefix
+			  (buffer-substring (point-min) (point)))
+		    (delete-region (point-min) (point))
+		    (insert fill-prefix)
+		    (add-hook 'filladapt-fill-paragraph-post-hook
+			      'filladapt-cleanup-kludge-at-point-min)))))
+	t ))))
+
+(defun filladapt-cleanup-kludge-at-point-min ()
+  "Cleanup the paragraph fill kludge.
+See filladapt-adapt."
+  (save-excursion
+    (goto-char (point-min))
+    (insert filladapt-old-line-prefix)
+    (delete-char (length fill-prefix))
+    (remove-hook 'filladapt-fill-paragraph-post-hook
+		 'filladapt-cleanup-kludge-at-point-min)))
+
+(defun filladapt-tail (list)
+  "Returns the last cons in LIST."
+  (if (null list)
+      nil
+    (while (consp (cdr list))
+      (setq list (cdr list)))
+    list ))
+
+(defun filladapt-delete-extent (e)
+  (if (fboundp 'delete-extent)
+      (delete-extent e)
+    (delete-overlay e)))
+
+(defun filladapt-make-extent (beg end)
+  (if (fboundp 'make-extent)
+      (make-extent beg end)
+    (make-overlay beg end)))
+
+(defun filladapt-set-extent-endpoints (e beg end)
+  (if (fboundp 'set-extent-endpoints)
+      (set-extent-endpoints e beg end)
+    (move-overlay e beg end)))
+
+(defun filladapt-set-extent-property (e prop val)
+  (if (fboundp 'set-extent-property)
+      (set-extent-property e prop val)
+    (overlay-put e prop val)))
+
+(defun filladapt-debug ()
+  "Toggle filladapt debugging on/off in the current buffer."
+;;  (interactive)
+  (make-local-variable 'filladapt-debug)
+  (setq filladapt-debug (not filladapt-debug))
+  (if (null filladapt-debug)
+      (progn
+	(mapcar (function (lambda (e) (filladapt-set-extent-endpoints e 1 1)))
+		filladapt-debug-indentation-extents)
+	(if filladapt-debug-paragraph-extent
+	    (progn
+	      (filladapt-delete-extent filladapt-debug-paragraph-extent)
+	      (setq filladapt-debug-paragraph-extent nil)))))
+  (add-hook 'post-command-hook 'filladapt-display-debug-info-maybe))
+
+(defun filladapt-display-debug-info-maybe ()
+  (cond ((null filladapt-debug) nil)
+	(fill-prefix nil)
+	(t
+	 (if (null filladapt-debug-paragraph-extent)
+	     (let ((e (filladapt-make-extent 1 1)))
+	       (filladapt-set-extent-property e 'detachable nil)
+	       (filladapt-set-extent-property e 'evaporate nil)
+	       (filladapt-set-extent-property e 'face
+					      filladapt-debug-paragraph-face)
+	       (setq filladapt-debug-paragraph-extent e)))
+	 (save-excursion
+	   (save-restriction
+	     (let ((ei-list filladapt-debug-indentation-extents)
+		   (ep filladapt-debug-paragraph-extent)
+		   (face filladapt-debug-indentation-face-1)
+		   fill-prefix token-list)
+	       (if (null (filladapt-adapt t t))
+		   (progn
+		     (filladapt-set-extent-endpoints ep 1 1)
+		     (while ei-list
+		       (filladapt-set-extent-endpoints (car ei-list) 1 1)
+		       (setq ei-list (cdr ei-list))))
+		 (filladapt-set-extent-endpoints ep (point-min) (point-max))
+		 (beginning-of-line)
+		 (setq token-list (filladapt-parse-prefixes))
+		 (message "(%s)" (mapconcat (function
+					   (lambda (q) (symbol-name (car q))))
+					  token-list
+					  " "))
+		 (while token-list
+		   (if ei-list
+		       (setq e (car ei-list)
+			     ei-list (cdr ei-list))
+		     (setq e (filladapt-make-extent 1 1))
+		     (filladapt-set-extent-property e 'detachable nil)
+		     (filladapt-set-extent-property e 'evaporate nil)
+		     (setq filladapt-debug-indentation-extents
+			   (cons e filladapt-debug-indentation-extents)))
+		   (filladapt-set-extent-property e 'face face)
+		   (filladapt-set-extent-endpoints e (point)
+						   (progn
+						     (move-to-column
+						      (nth 1
+							   (car token-list)))
+						     (point)))
+		   (if (eq face filladapt-debug-indentation-face-1)
+		       (setq face filladapt-debug-indentation-face-2)
+		     (setq face filladapt-debug-indentation-face-1))
+		   (setq token-list (cdr token-list)))
+		 (while ei-list
+		   (filladapt-set-extent-endpoints (car ei-list) 1 1)
+		   (setq ei-list (cdr ei-list))))))))))

File elisp/contrib/markdown-mode.el

View file
+;;; markdown-mode.el --- Emacs Major mode for Markdown-formatted text files
+
+;; Copyright (C) 2007-2011 Jason R. Blevins <jrblevin@sdf.org>
+;; Copyright (C) 2007, 2009 Edward O'Connor <ted@oconnor.cx>
+;; Copyright (C) 2007 Conal Elliott <conal@conal.net>
+;; Copyright (C) 2008 Greg Bognar <greg_bognar@hms.harvard.edu>
+;; Copyright (C) 2008 Dmitry Dzhus <mail@sphinx.net.ru>
+;; Copyright (C) 2008 Bryan Kyle <bryan.kyle@gmail.com>
+;; Copyright (C) 2008 Ben Voui <intrigeri@boum.org>
+;; Copyright (C) 2009 Ankit Solanki <ankit.solanki@gmail.com>
+;; Copyright (C) 2009 Hilko Bengen <bengen@debian.org>
+;; Copyright (C) 2009 Peter Williams <pezra@barelyenough.org>
+;; Copyright (C) 2010 George Ogata <george.ogata@gmail.com>
+;; Copyright (C) 2011 Eric Merritt <ericbmerritt@gmail.com>
+;; Copyright (C) 2011 Philippe Ivaldi <pivaldi@sfr.fr>
+;; Copyright (C) 2011 Jeremiah Dodds <jeremiah.dodds@gmail.com>
+
+;; Author: Jason R. Blevins <jrblevin@sdf.org>
+;; Maintainer: Jason R. Blevins <jrblevin@sdf.org>
+;; Created: May 24, 2007
+;; Version: 1.8.1
+;; Keywords: Markdown, GitHub Flavored Markdown, itex
+;; 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., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, 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.8.1, released on August 15, 2011:
+;;
+;;    * [markdown-mode.el][]
+;;    * [Screenshot][]
+;;    * [Release notes][]
+;;
+;;  [markdown-mode.el]: http://jblevins.org/projects/markdown-mode/markdown-mode.el
+;;  [screenshot]: http://jblevins.org/projects/markdown-mode/screenshots/20110812-001.png
+;;  [release notes]: http://jblevins.org/projects/markdown-mode/rev-1-8-1
+;;
+;; markdown-mode is also available in several package managers, including:
+;;
+;;    * Debian and Ubuntu Linux: [emacs-goodies-el][]
+;;    * RedHat and Fedora Linux: [emacs-goodies][]
+;;    * OpenBSD: [textproc/markdown-mode][]
+;;    * Arch Linux (AUR): [emacs-markdown-mode-git][]
+;;
+;;  [emacs-goodies-el]: http://packages.debian.org/emacs-goodies-el
+;;  [emacs-goodies]: https://admin.fedoraproject.org/pkgdb/acls/name/emacs-goodies
+;;  [textproc/markdown-mode]: http://pkgsrc.se/textproc/markdown-mode
+;;  [emacs-markdown-mode-git]: http://aur.archlinux.org/packages.php?ID=30389
+;;
+;; 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').  This variable may be customized to pass
+;;     command-line options to your Markdown processor of choice, but
+;;     this command must accept input from `stdin`.  If it does not, a
+;;     simple wrapper script can be used to write `stdin` to a file
+;;     and then pass that file to your Markdown interpreter.  Ideally,
+;;     this command will produce an XHTML fragment around which
+;;     markdown-mode will wrap a header and footer (which can be
+;;     further customized).  However, it attempts to detect whether
+;;     the command produces standalone XHTML output (via
+;;     `markdown-xhtml-standalone-regexp'), in which case no header
+;;     and footer content will be added.
+;;
+;;   * `markdown-command-needs-filename' - set to non-nil if
+;;     `markdown-command' does not accept input from stdin (default: nil).
+;;      Instead, it will be passed a filename as the final command-line
+;;      option.  As a result, you will only be able to run Markdown
+;;      from buffers which are visiting a file.
+;;
+;;   * `markdown-hr-string' - string to use when inserting horizontal
+;;     rules (default: `* * * * *').
+;;
+;;   * `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-follow-wiki-link-on-enter' - set to a non-nil value
+;;     to automatically open a linked document in a new buffer if the
+;;     cursor is an wiki link
+;;     (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').
+;;
+;;   * `markdown-css-path' - CSS file to link to in XHTML output.
+;;
+;;   * `markdown-xhtml-header-content' - additional content to include
+;;     in the XHTML `<head>` block.
+;;
+;;   * `markdown-xhtml-standalone-regexp' - a regular expression which
+;;     indicates whether the output of `markdown-command' is standalone
+;;     XHTML (default: `^\\(\<\?xml\\|\<!DOCTYPE\\|\<html\\)`).  If
+;;     this is not matched, we assume this output is a fragment and add
+;;     our own header and footer.
+;;
+;; 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 e` will run Markdown on the current buffer and save
+;;     the result in the file `basename.html`, where `basename` is the
+;;     name of the Markdown file with the extension removed.  **This
+;;     file will be overwritten without notice.**  Press `C-c C-c v`
+;;     to view the exported file 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 elements:
+;;
+;;     `C-c -` inserts a horizontal rule.
+;;
+;;   * Wiki-Link Navigation:
+;;
+;;     Use `M-p` and `M-n` to quickly jump to the previous and next
+;;     wiki links, respectively.
+;;
+;;   * Outline Navigation:
+;;
+;;     Navigation between headings is possible using `outline-mode'.
+;;     Use `C-M-n` and `C-M-p` to move between the next and previous
+;;     visible headings.  Similarly, `C-M-f` and `C-M-b` move to the
+;;     next and previous visible headings at the same level as the one
+;;     at the point.  Finally, `C-M-u` will move up to a lower-level
+;;     (more inclusive) visible heading.
+;;
+;; 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 attempts to be flexible in how it handles
+;; indentation.  When you press `TAB` repeatedly, the point will cycle
+;; through several possible indentation levels corresponding to things
+;; you might have in mind when you press `RET` at the end of a line or
+;; `TAB`.  For example, you may want to start a new list item,
+;; continue a list item with hanging indentation, indent for a nested
+;; pre block, and so on.
+;;
+;; 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. Wiki
+;; links may be followed automatically by hitting the enter key when
+;; your curser is on a wiki link or by hitting `C-c C-f`. The
+;; autofollowing on enter key may be controlled with the
+;; `markdown-follow-wiki-link-on-enter' customization.  Use `M-p` and
+;; `M-n` to quickly jump to the previous and next wiki links,
+;; respectively.  Aliased or piped wiki links of the form
+;; `[[PageName|link text]]` are also supported.
+;;
+;; [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.
+;;
+;; A [GitHub Flavored Markdown](http://github.github.com/github-flavored-markdown/)
+;; mode, `gfm-mode', is also available.  The GitHub implementation of
+;; differs slightly from standard Markdown.  Most importantly, newlines are
+;; significant and trigger hard line breaks.  As such, `gfm-mode' turns off
+;; `auto-fill-mode' and turns on `longlines-mode'.
+
+;;; 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 and
+;;     GitHub Flavored Markdown mode (`gfm-mode').
+;;   * Greg Bognar <greg_bognar@hms.harvard.edu> for menus and running
+;;     `markdown' with an active region.
+;;   * 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.
+;;   * Ben Voui <intrigeri@boum.org> for font-lock face customizations.
+;;   * Ankit Solanki <ankit.solanki@gmail.com> for longlines.el
+;;     compatibility and custom CSS.
+;;   * 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.
+;;   * Joost Kremers <j.kremers@em.uni-frankfurt.de> for bug reports
+;;     regarding indentation.
+;;   * Peter Williams <pezra@barelyenough.org> for fill-paragraph
+;;     enhancements.
+;;   * George Ogata <george.ogata@gmail.com> for fixing several
+;;     byte-compilation warnings.
+;;   * Eric Merritt <ericbmerritt@gmail.com> for wiki link features.
+;;   * Philippe Ivaldi <pivaldi@sfr.fr> for XHTML preview
+;;     customizations and XHTML export.
+;;   * Jeremiah Dodds <jeremiah.dodds@gmail.com> for supporting
+;;     Markdown processors which do not accept input from stdin.
+;;   * Werner Dittmann <werner.dittmann@t-online.de> for bug reports
+;;     regarding the cl dependency and auto-fill-mode and indentation.
+
+;;; Bugs:
+
+;; Although markdown-mode is developed and tested primarily using
+;; GNU Emacs 24, compatibility with earlier Emacsen is also a
+;; priority.
+;;
+;; If you find any bugs in markdown-mode, please construct a test case
+;; or a patch and email me at <jrblevin@sdf.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][]
+;;   * 2009-10-01: [Version 1.7][]
+;;   * 2011-08-12: [Version 1.8][]
+;;   * 2011-08-15: [Version 1.8.1][]
+;;
+;; [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
+;; [Version 1.8]: http://jblevins.org/projects/markdown-mode/rev-1-8
+;; [Version 1.8.1]: http://jblevins.org/projects/markdown-mode/rev-1-8-1
+
+
+;;; Code:
+
+(require 'easymenu)
+(require 'outline)
+(require 'cl)
+
+;;; Constants =================================================================
+
+(defconst markdown-mode-version "1.8.1"
+  "Markdown mode version number.")
+
+(defconst markdown-output-buffer-name "*markdown-output*"
+  "Name of temporary buffer for markdown command output.")
+
+;;; Customizable variables ====================================================
+
+(defvar markdown-mode-hook nil
+  "Hook runs when Markdown mode is loaded.")
+
+(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-command-needs-filename nil
+  "Set to non-nil if `markdown-command' does not accept input from stdin.
+Instead, it will be passed a filename as the final command-line
+option.  As a result, you will only be able to run Markdown from
+buffers which are visiting a file."
+  :group 'markdown
+  :type 'boolean)
+
+(defcustom markdown-hr-string "* * * * *"
+  "String to use for horizonal rules."
+  :group 'markdown
+  :type 'string)
+
+(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-follow-wiki-link-on-enter t
+  "Follow wiki link at point (if any) when the 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 ""
+  "URL of CSS file to link to in the output XHTML."
+  :group 'markdown
+  :type 'string)
+
+(defcustom markdown-xhtml-header-content ""
+  "Additional content to include in the XHTML <head> block."
+  :group 'markdown
+  :type 'string)
+
+(defcustom markdown-xhtml-standalone-regexp
+  "^\\(\<\?xml\\|\<!DOCTYPE\\|\<html\\)"
+  "Regexp indicating whether `markdown-command' output is standalone XHTML."
+  :group 'markdown
+  :type 'regexp)
+
+;;; 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.")