Browse Source

Split out org-list.el from org.el and org-export-latex.el.

Carsten Dominik 16 years ago
parent
commit
f0f34d4985
5 changed files with 1082 additions and 1016 deletions
  1. 3 1
      Makefile
  2. 3 0
      lisp/ChangeLog
  3. 0 252
      lisp/org-export-latex.el
  4. 1039 0
      lisp/org-list.el
  5. 37 763
      lisp/org.el

+ 3 - 1
Makefile

@@ -74,6 +74,7 @@ LISPF      = 	org.el			\
 		org-info.el		\
 		org-jsinfo.el		\
 		org-irc.el		\
+		org-list.el		\
 		org-mac-message.el	\
 	     	org-macs.el		\
 		org-mew.el              \
@@ -299,12 +300,13 @@ lisp/org-id.elc:           lisp/org.elc
 lisp/org-info.elc:         lisp/org.elc
 lisp/org-irc.elc:          lisp/org.elc
 lisp/org-jsinfo.elc:       lisp/org.elc lisp/org-exp.elc
-lisp/org-plot.elc:         lisp/org.elc lisp/org-exp.elc lisp/org-table.elc
+lisp/org-list.elc:         lisp/org-macs.elc lisp/org-compat.elc
 lisp/org-mac-message.elc:  lisp/org.elc
 lisp/org-macs.elc:
 lisp/org-mew.elc:          lisp/org.elc
 lisp/org-mhe.elc:          lisp/org.elc
 lisp/org-mouse.elc:        lisp/org.elc
+lisp/org-plot.elc:         lisp/org.elc lisp/org-exp.elc lisp/org-table.elc
 lisp/org-publish.elc:
 lisp/org-remember.elc:     lisp/org.elc
 lisp/org-rmail.elc:        lisp/org.elc

+ 3 - 0
lisp/ChangeLog

@@ -1,5 +1,8 @@
 2008-09-23  Carsten Dominik  <dominik@science.uva.nl>
 
+	* org-list.el: New file, aggregating list functions from org.el
+	and org-export-latex.el.
+
 	* org.el (org-edit-src-region-extra): New option.
 
 2008-09-22  Carsten Dominik  <dominik@science.uva.nl>

+ 0 - 252
lisp/org-export-latex.el

@@ -67,9 +67,6 @@
     org-clock-string)
   "A list of regexps to convert as special keywords.")
 
-(defvar org-list-beginning-re
-  "^\\([ \t]*\\)\\([-+*]\\|[0-9]+[.)]\\) +\\(.*\\)$")
-
 (defvar latexp)    ; dynamically scoped from org.el
 (defvar re-quote)  ; dynamically scoped from org.el
 (defvar commentsp) ; dynamically scoped from org.el
@@ -227,33 +224,6 @@ Don't remove the keys, just change their values."
   :group 'org-export-latex
   :type 'coding-system)
 
-(defcustom org-list-radio-list-templates
-  '((latex-mode "% BEGIN RECEIVE ORGLST %n
-% END RECEIVE ORGLST %n
-\\begin{comment}
-#+ORGLST: SEND %n org-list-to-latex
-| | |
-\\end{comment}\n")
-    (texinfo-mode "@c BEGIN RECEIVE ORGLST %n
-@c END RECEIVE ORGLST %n
-@ignore
-#+ORGLST: SEND %n org-list-to-texinfo
-| | |
-@end ignore\n")
-    (html-mode "<!-- BEGIN RECEIVE ORGLST %n -->
-<!-- END RECEIVE ORGLST %n -->
-<!--
-#+ORGLST: SEND %n org-list-to-html
-| | |
--->\n"))
-  "Templates for radio lists in different major modes.
-All occurrences of %n in a template will be replaced with the name of the
-list, obtained by prompting the user."
-  :group 'org-plain-lists
-  :type '(repeat
-	  (list (symbol :tag "Major mode")
-		(string :tag "Format"))))
-
 ;;; Autoload functions:
 
 ;;;###autoload
@@ -1225,228 +1195,6 @@ If TIMESTAMPS, convert timestamps, otherwise delete them."
     (beginning-of-line)
     (insert (org-list-to-latex (org-list-parse-list t)) "\n")))
 
-(defun org-list-parse-list (&optional delete)
-  "Parse the list at point and maybe DELETE it.
-Return a list containing first level items as strings and
-sublevels as a list of strings."
-  (let* ((item-beginning (org-list-item-beginning))
-         (start (car item-beginning))
-         (end (org-list-end (cdr item-beginning)))
-         output itemsep ltype)
-    (while (re-search-forward org-list-beginning-re end t)
-      (goto-char (match-beginning 3))
-      (save-match-data
-        (cond ((string-match "[0-9]" (match-string 2))
-               (setq itemsep "[0-9]+\\(?:\\.\\|)\\)"
-                     ltype 'ordered))
-              ((string-match "^.*::" (match-string 0))
-               (setq itemsep "[-+]" ltype 'descriptive))
-              (t (setq itemsep "[-+]" ltype 'unordered))))
-      (let* ((indent1 (match-string 1))
-	     (nextitem (save-excursion
-			 (save-match-data
-			   (or (and (re-search-forward
-				     (concat "^" indent1 itemsep " *?") end t)
-				    (match-beginning 0)) end))))
-	     (item (buffer-substring
-		    (point)
-		    (or (and (re-search-forward
-			      org-list-beginning-re end t)
-			     (goto-char (match-beginning 0)))
-			(goto-char end))))
-	     (nextindent (match-string 1))
-	     (item (org-trim item))
-	     (item (if (string-match "^\\[.+\\]" item)
-		       (replace-match "\\\\texttt{\\&}"
-				      t nil item) item)))
-	(push item output)
-	(when (> (length nextindent)
-		 (length indent1))
-	  (narrow-to-region (point) nextitem)
-	  (push (org-list-parse-list) output)
-	  (widen))))
-    (when delete (delete-region start end))
-    (setq output (nreverse output))
-    (push ltype output)))
-
-(defun org-list-item-beginning ()
-  "Find the beginning of the list item.
-Return a cons which car is the beginning position of the item and
-cdr is the indentation string."
-  (save-excursion
-    (if (not (or (looking-at org-list-beginning-re)
-		 (re-search-backward
-		  org-list-beginning-re nil t)))
-	(progn (goto-char (point-min)) (point))
-      (cons (match-beginning 0) (match-string 1)))))
-
-(defun org-list-end (indent)
-  "Return the position of the end of the list.
-INDENT is the indentation of the list."
-  (save-excursion
-    (catch 'exit
-      (while (or (looking-at org-list-beginning-re)
-		 (looking-at (concat "^" indent "[ \t]+\\|^$")))
-	(if (eq (point) (point-max))
-	    (throw 'exit (point-max)))
-	(forward-line 1))) (point)))
-
-(defun org-list-insert-radio-list ()
-  "Insert a radio list template appropriate for this major mode."
-  (interactive)
-  (let* ((e (assq major-mode org-list-radio-list-templates))
-	 (txt (nth 1 e))
-	 name pos)
-    (unless e (error "No radio list setup defined for %s" major-mode))
-    (setq name (read-string "List name: "))
-    (while (string-match "%n" txt)
-      (setq txt (replace-match name t t txt)))
-    (or (bolp) (insert "\n"))
-    (setq pos (point))
-    (insert txt)
-    (goto-char pos)))
-
-(defun org-list-send-list (&optional maybe)
-  "Send a tranformed version of this list to the receiver position.
-With argument MAYBE, fail quietly if no transformation is defined for
-this list."
-  (interactive)
-  (catch 'exit
-    (unless (org-at-item-p) (error "Not at a list"))
-    (save-excursion
-      (goto-char (car (org-list-item-beginning)))
-      (beginning-of-line 0)
-      (unless (looking-at "#\\+ORGLST: *SEND +\\([a-zA-Z0-9_]+\\) +\\([^ \t\r\n]+\\)\\( +.*\\)?")
-	(if maybe
-	    (throw 'exit nil)
-	  (error "Don't know how to transform this list"))))
-    (let* ((name (match-string 1))
-           (item-beginning (org-list-item-beginning))
-	   (transform (intern (match-string 2)))
-	   (txt (buffer-substring-no-properties
-                 (car item-beginning)
-		 (org-list-end (cdr item-beginning))))
-	   (list (org-list-parse-list))
-           beg)
-      (unless (fboundp transform)
-	(error "No such transformation function %s" transform))
-      (setq txt (funcall transform list))
-      ;; Find the insertion place
-      (save-excursion
-	(goto-char (point-min))
-	(unless (re-search-forward
-		 (concat "BEGIN RECEIVE ORGLST +" name "\\([ \t]\\|$\\)") nil t)
-	  (error "Don't know where to insert translated list"))
-	(goto-char (match-beginning 0))
-	(beginning-of-line 2)
-	(setq beg (point))
-	(unless (re-search-forward (concat "END RECEIVE ORGLST +" name) nil t)
-	  (error "Cannot find end of insertion region"))
-	(beginning-of-line 1)
-	(delete-region beg (point))
-	(goto-char beg)
-	(insert txt "\n"))
-      (message "List converted and installed at receiver location"))))
-
-(defun org-list-to-generic (list params)
-  "Convert a LIST parsed through `org-list-parse-list' to other formats.
-
-Valid parameters PARAMS are
-
-:ustart     String to start an unordered list
-:uend       String to end an unordered list
-
-:ostart     String to start an ordered list
-:oend       String to end an ordered list
-
-:dstart     String to start a descriptive list
-:dend       String to end a descriptive list
-:dtstart    String to start a descriptive term
-:dtend      String to end a descriptive term
-:ddstart    String to start a description
-:ddend      String to end a description
-
-:splice     When set to t, return only list body lines, don't wrap
-            them into :[u/o]start and :[u/o]end.  Default is nil.
-
-:istart     String to start a list item
-:iend       String to end a list item
-:isep       String to separate items
-:lsep       String to separate sublists"
-  (interactive)
-  (let* ((p params) sublist
-	 (splicep (plist-get p :splice))
-	 (ostart  (plist-get p :ostart))
-	 (oend  (plist-get p :oend))
-	 (ustart  (plist-get p :ustart))
-	 (uend  (plist-get p :uend))
-	 (dstart  (plist-get p :dstart))
-	 (dend  (plist-get p :dend))
-	 (dtstart  (plist-get p :dtstart))
-	 (dtend  (plist-get p :dtend))
-	 (ddstart  (plist-get p :ddstart))
-	 (ddend  (plist-get p :ddend))
-	 (istart  (plist-get p :istart))
-	 (iend  (plist-get p :iend))
-	 (isep  (plist-get p :isep))
-	 (lsep  (plist-get p :lsep)))
-    (let ((wrapper
-	   (cond ((eq (car list) 'ordered)
-		  (concat ostart "\n%s" oend "\n"))
-		 ((eq (car list) 'unordered)
-		  (concat ustart "\n%s" uend "\n"))
-		 ((eq (car list) 'descriptive)
-		  (concat dstart "\n%s" dend "\n"))))
-	  rtn term defstart defend)
-      (while (setq sublist (pop list))
-	(cond ((symbolp sublist) nil)
-	      ((stringp sublist)
-               (when (string-match "^\\(.*\\) ::" sublist)
-                 (setq term (org-trim (format (concat dtstart "%s" dtend)
-                                              (match-string 1 sublist))))
-                 (setq sublist (substring sublist (1+ (length term)))))
-               (setq rtn (concat rtn istart term ddstart
-                                 sublist ddend iend isep)))
-              (t (setq rtn (concat rtn   ;; previous list
-                                   lsep  ;; list separator
-                                   (org-list-to-generic sublist p)
-                                   lsep  ;; list separator
-                                   )))))
-      (format wrapper rtn))))
-
-(defun org-list-to-latex (list)
-  "Convert LIST into a LaTeX list."
-  (org-list-to-generic
-   list '(:splicep nil :ostart "\\begin{enumerate}" :oend "\\end{enumerate}"
-                       :ustart "\\begin{itemize}" :uend "\\end{itemize}"
-                       :dstart "\\begin{description}" :dend "\\end{description}"
-                       :dtstart "[" :dtend "]"
-                       :ddstart "" :ddend ""
-                       :istart "\\item " :iend ""
-                       :isep "\n" :lsep "\n")))
-
-(defun org-list-to-html (list)
-  "Convert LIST into a HTML list."
-  (org-list-to-generic
-   list '(:splicep nil :ostart "<ol>" :oend "</ol>"
-                       :ustart "<ul>" :uend "</ul>"
-                       :dstart "<dl>" :dend "</dl>"
-                       :dtstart "<dt>" :dtend "</dt>"
-                       :ddstart "<dd>" :ddend "</dd>"
-                       :istart "<li>" :iend "</li>"
-                       :isep "\n" :lsep "\n")))
-
-(defun org-list-to-texinfo (list)
-  "Convert LIST into a Texinfo list."
-  (org-list-to-generic
-   list '(:splicep nil :ostart "@itemize @minus" :oend "@end itemize"
-                       :ustart "@enumerate" :uend "@end enumerate"
-                       :dstart "@table" :dend "@end table"
-                       :dtstart "@item " :dtend "\n"
-                       :ddstart "" :ddend ""
-                       :istart "@item\n" :iend ""
-                       :isep "\n" :lsep "\n")))
-
 (defconst org-latex-entities
  '("\\!"
    "\\'"

+ 1039 - 0
lisp/org-list.el

@@ -0,0 +1,1039 @@
+;;; org-list.el --- Plain lists for Org-mode
+;;
+;; Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;;
+;; Author: Carsten Dominik <carsten at orgmode dot org>
+;;         Bastien Guerry <bzg AT altern DOT org>
+;; Keywords: outlines, hypermedia, calendar, wp
+;; Homepage: http://orgmode.org
+;; Version: 6.08-pre01
+;;
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs 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 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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.  If not, see <http://www.gnu.org/licenses/>.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Commentary:
+
+;; This file contains the code dealing with plain lists in Org-mode.
+
+;;; Code:
+
+(require 'org-macs)
+(require 'org-compat)
+
+(defvar org-blank-before-new-entry)
+(defvar org-M-RET-may-split-line)
+
+(declare-function org-invisible-p "org" ())
+(declare-function org-on-heading-p "org" (&optional invisible-ok))
+(declare-function outline-next-heading "org" ())
+(declare-function outline-back-to-heading "org" (&optional invisible-ok))
+(declare-function org-back-to-heading "org" (&optional invisible-ok))
+(declare-function org-back-over-empty-lines "org" ())
+(declare-function org-skip-whitespace "org" ())
+(declare-function org-trim "org" (s))
+(declare-function org-get-indentation "org" (&optional line))
+
+(defgroup org-plain-lists nil
+  "Options concerning plain lists in Org-mode."
+  :tag "Org Plain lists"
+  :group 'org-structure)
+
+(defcustom org-cycle-include-plain-lists nil
+  "Non-nil means, include plain lists into visibility cycling.
+This means that during cycling, plain list items will *temporarily* be
+interpreted as outline headlines with a level given by 1000+i where i is the
+indentation of the bullet.  In all other operations, plain list items are
+not seen as headlines.  For example, you cannot assign a TODO keyword to
+such an item."
+  :group 'org-plain-lists
+  :type 'boolean)
+
+(defcustom org-plain-list-ordered-item-terminator t
+  "The character that makes a line with leading number an ordered list item.
+Valid values are ?. and ?\).  To get both terminators, use t.  While
+?. may look nicer, it creates the danger that a line with leading
+number may be incorrectly interpreted as an item.  ?\) therefore is
+the safe choice."
+  :group 'org-plain-lists
+  :type '(choice (const :tag "dot like in \"2.\"" ?.)
+		 (const :tag "paren like in \"2)\"" ?\))
+		 (const :tab "both" t)))
+
+(defcustom org-empty-line-terminates-plain-lists nil
+  "Non-nil means, an empty line ends all plain list levels.
+When nil, empty lines are part of the preceeding item."
+  :group 'org-plain-lists
+  :type 'boolean)
+
+(defcustom org-auto-renumber-ordered-lists t
+  "Non-nil means, automatically renumber ordered plain lists.
+Renumbering happens when the sequence have been changed with
+\\[org-shiftmetaup] or \\[org-shiftmetadown].  After other editing commands,
+use \\[org-ctrl-c-ctrl-c] to trigger renumbering."
+  :group 'org-plain-lists
+  :type 'boolean)
+
+(defcustom org-provide-checkbox-statistics t
+  "Non-nil means, update checkbox statistics after insert and toggle.
+When this is set, checkbox statistics is updated each time you either insert
+a new checkbox with \\[org-insert-todo-heading] or toggle a checkbox
+with \\[org-ctrl-c-ctrl-c\\]."
+  :group 'org-plain-lists
+  :type 'boolean)
+
+(defcustom org-description-max-indent 20
+  "Maximum indentation for the second line of a description list.
+When the indentation would be larger than this, it will become
+5 characters instead."
+  :group 'org-plain-lists
+  :type 'integer)
+
+(defvar org-list-beginning-re
+  "^\\([ \t]*\\)\\([-+*]\\|[0-9]+[.)]\\) +\\(.*\\)$")
+
+(defcustom org-list-radio-list-templates
+  '((latex-mode "% BEGIN RECEIVE ORGLST %n
+% END RECEIVE ORGLST %n
+\\begin{comment}
+#+ORGLST: SEND %n org-list-to-latex
+| | |
+\\end{comment}\n")
+    (texinfo-mode "@c BEGIN RECEIVE ORGLST %n
+@c END RECEIVE ORGLST %n
+@ignore
+#+ORGLST: SEND %n org-list-to-texinfo
+| | |
+@end ignore\n")
+    (html-mode "<!-- BEGIN RECEIVE ORGLST %n -->
+<!-- END RECEIVE ORGLST %n -->
+<!--
+#+ORGLST: SEND %n org-list-to-html
+| | |
+-->\n"))
+  "Templates for radio lists in different major modes.
+All occurrences of %n in a template will be replaced with the name of the
+list, obtained by prompting the user."
+  :group 'org-plain-lists
+  :type '(repeat
+	  (list (symbol :tag "Major mode")
+		(string :tag "Format"))))
+
+;;;; Plain list items, including checkboxes
+
+;;; Plain list items
+
+(defun org-at-item-p ()
+  "Is point in a line starting a hand-formatted item?"
+  (let ((llt org-plain-list-ordered-item-terminator))
+    (save-excursion
+      (goto-char (point-at-bol))
+      (looking-at
+       (cond
+	((eq llt t)  "\\([ \t]*\\([-+]\\|\\([0-9]+[.)]\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)")
+	((= llt ?.)  "\\([ \t]*\\([-+]\\|\\([0-9]+\\.\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)")
+	((= llt ?\)) "\\([ \t]*\\([-+]\\|\\([0-9]+))\\)\\|[ \t]+\\*\\)\\( \\|$\\)")
+	(t (error "Invalid value of `org-plain-list-ordered-item-terminator'")))))))
+
+(defun org-in-item-p ()
+  "It the cursor inside a plain list item.
+Does not have to be the first line."
+  (save-excursion
+    (condition-case nil
+	(progn
+	  (org-beginning-of-item)
+	  (org-at-item-p)
+	  t)
+      (error nil))))
+
+(defun org-insert-item (&optional checkbox)
+  "Insert a new item at the current level.
+Return t when things worked, nil when we are not in an item."
+  (when (save-excursion
+	  (condition-case nil
+	      (progn
+		(org-beginning-of-item)
+		(org-at-item-p)
+		(if (org-invisible-p) (error "Invisible item"))
+		t)
+	    (error nil)))
+    (let* ((bul (match-string 0))
+	   (descp (save-excursion (goto-char (match-beginning 0))
+				  (beginning-of-line 1)
+				  (save-match-data
+				    (looking-at "[ \t]*.*? ::"))))
+	   (eow (save-excursion (beginning-of-line 1) (looking-at "[ \t]*")
+				(match-end 0)))
+	   (blank (cdr (assq 'plain-list-item org-blank-before-new-entry)))
+	   pos)
+      (if descp (setq checkbox nil))
+      (cond
+       ((and (org-at-item-p) (<= (point) eow))
+	;; before the bullet
+	(beginning-of-line 1)
+	(open-line (if blank 2 1)))
+       ((<= (point) eow)
+	(beginning-of-line 1))
+       (t
+	(unless (org-get-alist-option org-M-RET-may-split-line 'item)
+	  (end-of-line 1)
+	  (delete-horizontal-space))
+	(newline (if blank 2 1))))
+      (insert bul
+	      (if checkbox "[ ]" "")
+	      (if descp (concat (if checkbox " " "")
+				(read-string "Term: ") " :: ") ""))
+      (just-one-space)
+      (setq pos (point))
+      (end-of-line 1)
+      (unless (= (point) pos) (just-one-space) (backward-delete-char 1)))
+    (org-maybe-renumber-ordered-list)
+    (and checkbox (org-update-checkbox-count-maybe))
+    t))
+
+;;; Checkboxes
+
+(defun org-at-item-checkbox-p ()
+  "Is point at a line starting a plain-list item with a checklet?"
+  (and (org-at-item-p)
+       (save-excursion
+	 (goto-char (match-end 0))
+	 (skip-chars-forward " \t")
+	 (looking-at "\\[[- X]\\]"))))
+
+(defun org-toggle-checkbox (&optional arg)
+  "Toggle the checkbox in the current line."
+  (interactive "P")
+  (catch 'exit
+    (let (beg end status (firstnew 'unknown))
+      (cond
+       ((org-region-active-p)
+	(setq beg (region-beginning) end (region-end)))
+       ((org-on-heading-p)
+	(setq beg (point) end (save-excursion (outline-next-heading) (point))))
+       ((org-at-item-checkbox-p)
+	(let ((pos (point)))
+	  (replace-match
+	   (cond (arg "[-]")
+		 ((member (match-string 0) '("[ ]" "[-]")) "[X]")
+		 (t "[ ]"))
+	   t t)
+	  (goto-char pos))
+	(throw 'exit t))
+       (t (error "Not at a checkbox or heading, and no active region")))
+      (save-excursion
+	(goto-char beg)
+	(while (< (point) end)
+	  (when (org-at-item-checkbox-p)
+	    (setq status (equal (match-string 0) "[X]"))
+	    (when (eq firstnew 'unknown)
+	      (setq firstnew (not status)))
+	    (replace-match
+	     (if (if arg (not status) firstnew) "[X]" "[ ]") t t))
+	  (beginning-of-line 2)))))
+  (org-update-checkbox-count-maybe))
+
+(defun org-update-checkbox-count-maybe ()
+  "Update checkbox statistics unless turned off by user."
+  (when org-provide-checkbox-statistics
+    (org-update-checkbox-count)))
+
+(defun org-update-checkbox-count (&optional all)
+ "Update the checkbox statistics in the current section.
+This will find all statistic cookies like [57%] and [6/12] and update them
+with the current numbers.  With optional prefix argument ALL, do this for
+the whole buffer."
+ (interactive "P")
+ (save-excursion
+   (let* ((buffer-invisibility-spec (org-inhibit-invisibility)) ; Emacs 21
+	  (beg (condition-case nil
+		   (progn (outline-back-to-heading) (point))
+		 (error (point-min))))
+	  (end (move-marker (make-marker)
+			    (progn (outline-next-heading) (point))))
+	  (re "\\(\\(\\[[0-9]*%\\]\\)\\|\\(\\[[0-9]*/[0-9]*\\]\\)\\)")
+	  (re-box "^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +\\(\\[[- X]\\]\\)")
+	  (re-find (concat re "\\|" re-box))
+	  beg-cookie end-cookie is-percent c-on c-off lim
+          eline curr-ind next-ind continue-from startsearch
+          (cstat 0)
+          )
+     (when all
+       (goto-char (point-min))
+       (outline-next-heading)
+       (setq beg (point) end (point-max)))
+     (goto-char end)
+     ;; find each statistic cookie
+     (while (re-search-backward re-find beg t)
+       (setq beg-cookie (match-beginning 1)
+             end-cookie (match-end 1)
+	     cstat (+ cstat (if end-cookie 1 0))
+	     startsearch (point-at-eol)
+	     continue-from (point-at-bol)
+             is-percent (match-beginning 2)
+	     lim (cond
+		  ((org-on-heading-p) (outline-next-heading) (point))
+		  ((org-at-item-p) (org-end-of-item) (point))
+		  (t nil))
+             c-on 0
+             c-off 0)
+       (when lim
+         ;; find first checkbox for this cookie and gather
+         ;; statistics from all that are at this indentation level
+         (goto-char startsearch)
+         (if (re-search-forward re-box lim t)
+             (progn
+               (org-beginning-of-item)
+               (setq curr-ind (org-get-indentation))
+               (setq next-ind curr-ind)
+               (while (and (bolp) (org-at-item-p) (= curr-ind next-ind))
+                 (save-excursion (end-of-line) (setq eline (point)))
+                 (if (re-search-forward re-box eline t)
+		     (if (member (match-string 2) '("[ ]" "[-]"))
+			 (setq c-off (1+ c-off))
+                       (setq c-on (1+ c-on))
+                       )
+                   )
+                 (org-end-of-item)
+                 (setq next-ind (org-get-indentation))
+                 )))
+	 (goto-char continue-from)
+         ;; update cookie
+	 (when end-cookie
+	   (delete-region beg-cookie end-cookie)
+	   (goto-char beg-cookie)
+	   (insert
+	    (if is-percent
+		(format "[%d%%]" (/ (* 100 c-on) (max 1 (+ c-on c-off))))
+	      (format "[%d/%d]" c-on (+ c-on c-off)))))
+         ;; update items checkbox if it has one
+         (when (org-at-item-p)
+           (org-beginning-of-item)
+           (when (and (> (+ c-on c-off) 0)
+		      (re-search-forward re-box (point-at-eol) t))
+             (setq beg-cookie (match-beginning 2)
+                   end-cookie (match-end       2))
+             (delete-region beg-cookie end-cookie)
+             (goto-char beg-cookie)
+             (cond ((= c-off 0) (insert "[X]"))
+                   ((= c-on  0) (insert "[ ]"))
+                   (t           (insert "[-]")))
+             )))
+       (goto-char continue-from))
+     (when (interactive-p)
+       (message "Checkbox satistics updated %s (%d places)"
+		(if all "in entire file" "in current outline entry") cstat)))))
+
+(defun org-get-checkbox-statistics-face ()
+  "Select the face for checkbox statistics.
+The face will be `org-done' when all relevant boxes are checked.  Otherwise
+it will be `org-todo'."
+  (if (match-end 1)
+      (if (equal (match-string 1) "100%") 'org-done 'org-todo)
+    (if (and (> (match-end 2) (match-beginning 2))
+	     (equal (match-string 2) (match-string 3)))
+	'org-done
+      'org-todo)))
+
+(defun org-beginning-of-item ()
+  "Go to the beginning of the current hand-formatted item.
+If the cursor is not in an item, throw an error."
+  (interactive)
+  (let ((pos (point))
+	(limit (save-excursion
+		 (condition-case nil
+		     (progn
+		       (org-back-to-heading)
+		       (beginning-of-line 2) (point))
+		   (error (point-min)))))
+	(ind-empty (if org-empty-line-terminates-plain-lists 0 10000))
+	ind ind1)
+    (if (org-at-item-p)
+	(beginning-of-line 1)
+      (beginning-of-line 1)
+      (skip-chars-forward " \t")
+      (setq ind (current-column))
+      (if (catch 'exit
+	    (while t
+	      (beginning-of-line 0)
+	      (if (or (bobp) (< (point) limit)) (throw 'exit nil))
+
+	      (if (looking-at "[ \t]*$")
+		  (setq ind1 ind-empty)
+		(skip-chars-forward " \t")
+		(setq ind1 (current-column)))
+	      (if (< ind1 ind)
+		  (progn (beginning-of-line 1) (throw 'exit (org-at-item-p))))))
+	  nil
+	(goto-char pos)
+	(error "Not in an item")))))
+
+(defun org-end-of-item ()
+  "Go to the end of the current hand-formatted item.
+If the cursor is not in an item, throw an error."
+  (interactive)
+  (let* ((pos (point))
+	 ind1
+	 (ind-empty (if org-empty-line-terminates-plain-lists 0 10000))
+	 (limit (save-excursion (outline-next-heading) (point)))
+	 (ind (save-excursion
+		(org-beginning-of-item)
+		(skip-chars-forward " \t")
+		(current-column)))
+	 (end (catch 'exit
+		(while t
+		  (beginning-of-line 2)
+		  (if (eobp) (throw 'exit (point)))
+		  (if (>= (point) limit) (throw 'exit (point-at-bol)))
+		  (if (looking-at "[ \t]*$")
+		      (setq ind1 ind-empty)
+		    (skip-chars-forward " \t")
+		    (setq ind1 (current-column)))
+		  (if (<= ind1 ind)
+		      (throw 'exit (point-at-bol)))))))
+    (if end
+	(goto-char end)
+      (goto-char pos)
+      (error "Not in an item"))))
+
+(defun org-next-item ()
+  "Move to the beginning of the next item in the current plain list.
+Error if not at a plain list, or if this is the last item in the list."
+  (interactive)
+  (let (ind ind1 (pos (point)))
+    (org-beginning-of-item)
+    (setq ind (org-get-indentation))
+    (org-end-of-item)
+    (setq ind1 (org-get-indentation))
+    (unless (and (org-at-item-p) (= ind ind1))
+      (goto-char pos)
+      (error "On last item"))))
+
+(defun org-previous-item ()
+  "Move to the beginning of the previous item in the current plain list.
+Error if not at a plain list, or if this is the first item in the list."
+  (interactive)
+  (let (beg ind ind1 (pos (point)))
+    (org-beginning-of-item)
+    (setq beg (point))
+    (setq ind (org-get-indentation))
+    (goto-char beg)
+    (catch 'exit
+      (while t
+	(beginning-of-line 0)
+	(if (looking-at "[ \t]*$")
+	    nil
+	  (if (<= (setq ind1 (org-get-indentation)) ind)
+	      (throw 'exit t)))))
+    (condition-case nil
+	(if (or (not (org-at-item-p))
+		(< ind1 (1- ind)))
+	    (error "")
+	  (org-beginning-of-item))
+      (error (goto-char pos)
+	     (error "On first item")))))
+
+(defun org-first-list-item-p ()
+  "Is this heading the item in a plain list?"
+  (unless (org-at-item-p)
+    (error "Not at a plain list item"))
+  (org-beginning-of-item)
+  (= (point) (save-excursion (org-beginning-of-item-list))))
+
+(defun org-move-item-down ()
+  "Move the plain list item at point down, i.e. swap with following item.
+Subitems (items with larger indentation) are considered part of the item,
+so this really moves item trees."
+  (interactive)
+  (let (beg beg0 end end0 ind ind1 (pos (point)) txt ne-end ne-beg)
+    (org-beginning-of-item)
+    (setq beg0 (point))
+    (save-excursion
+      (setq ne-beg (org-back-over-empty-lines))
+      (setq beg (point)))
+    (goto-char beg0)
+    (setq ind (org-get-indentation))
+    (org-end-of-item)
+    (setq end0 (point))
+    (setq ind1 (org-get-indentation))
+    (setq ne-end (org-back-over-empty-lines))
+    (setq end (point))
+    (goto-char beg0)
+    (when (and (org-first-list-item-p) (< ne-end ne-beg))
+      ;; include less whitespace
+      (save-excursion
+	(goto-char beg)
+	(forward-line (- ne-beg ne-end))
+	(setq beg (point))))
+    (goto-char end0)
+    (if (and (org-at-item-p) (= ind ind1))
+	(progn
+	  (org-end-of-item)
+	  (org-back-over-empty-lines)
+	  (setq txt (buffer-substring beg end))
+	  (save-excursion
+	    (delete-region beg end))
+	  (setq pos (point))
+	  (insert txt)
+	  (goto-char pos) (org-skip-whitespace)
+	  (org-maybe-renumber-ordered-list))
+      (goto-char pos)
+      (error "Cannot move this item further down"))))
+
+(defun org-move-item-up (arg)
+  "Move the plain list item at point up, i.e. swap with previous item.
+Subitems (items with larger indentation) are considered part of the item,
+so this really moves item trees."
+  (interactive "p")
+  (let (beg beg0 end ind ind1 (pos (point)) txt
+	    ne-beg ne-ins ins-end)
+    (org-beginning-of-item)
+    (setq beg0 (point))
+    (setq ind (org-get-indentation))
+    (save-excursion
+      (setq ne-beg (org-back-over-empty-lines))
+      (setq beg (point)))
+    (goto-char beg0)
+    (org-end-of-item)
+    (org-back-over-empty-lines)
+    (setq end (point))
+    (goto-char beg0)
+    (catch 'exit
+      (while t
+	(beginning-of-line 0)
+	(if (looking-at "[ \t]*$")
+	    (if org-empty-line-terminates-plain-lists
+		(progn
+		  (goto-char pos)
+		  (error "Cannot move this item further up"))
+	      nil)
+	  (if (<= (setq ind1 (org-get-indentation)) ind)
+	      (throw 'exit t)))))
+    (condition-case nil
+	(org-beginning-of-item)
+      (error (goto-char beg0)
+	     (error "Cannot move this item further up")))
+    (setq ind1 (org-get-indentation))
+    (if (and (org-at-item-p) (= ind ind1))
+	(progn
+	  (setq ne-ins (org-back-over-empty-lines))
+	  (setq txt (buffer-substring beg end))
+	  (save-excursion
+	    (delete-region beg end))
+	  (setq pos (point))
+	  (insert txt)
+	  (setq ins-end (point))
+	  (goto-char pos) (org-skip-whitespace)
+
+	  (when (and (org-first-list-item-p) (> ne-ins ne-beg))
+	    ;; Move whitespace back to beginning
+	    (save-excursion
+	      (goto-char ins-end)
+	      (let ((kill-whole-line t))
+		(kill-line (- ne-ins ne-beg)) (point)))
+	    (insert (make-string (- ne-ins ne-beg) ?\n)))
+
+	  (org-maybe-renumber-ordered-list))
+      (goto-char pos)
+      (error "Cannot move this item further up"))))
+
+(defun org-maybe-renumber-ordered-list ()
+  "Renumber the ordered list at point if setup allows it.
+This tests the user option `org-auto-renumber-ordered-lists' before
+doing the renumbering."
+  (interactive)
+  (when (and org-auto-renumber-ordered-lists
+	     (org-at-item-p))
+    (if (match-beginning 3)
+	(org-renumber-ordered-list 1)
+      (org-fix-bullet-type))))
+
+(defun org-maybe-renumber-ordered-list-safe ()
+  (condition-case nil
+      (save-excursion
+	(org-maybe-renumber-ordered-list))
+    (error nil)))
+
+(defun org-cycle-list-bullet (&optional which)
+  "Cycle through the different itemize/enumerate bullets.
+This cycle the entire list level through the sequence:
+
+   `-'  ->  `+'  ->  `*'  ->  `1.'  ->  `1)'
+
+If WHICH is a string, use that as the new bullet.  If WHICH is an integer,
+0 meand `-', 1 means `+' etc."
+  (interactive "P")
+  (org-preserve-lc
+   (org-beginning-of-item-list)
+   (org-at-item-p)
+   (beginning-of-line 1)
+   (let ((current (match-string 0))
+	 (prevp (eq which 'previous))
+	 new)
+     (setq new (cond
+		((and (numberp which)
+		      (nth (1- which) '("-" "+" "*" "1." "1)"))))
+		((string-match "-" current) (if prevp "1)" "+"))
+		((string-match "\\+" current)
+		 (if prevp "-" (if (looking-at "\\S-") "1." "*")))
+		((string-match "\\*" current) (if prevp "+" "1."))
+		((string-match "\\." current) (if prevp "*" "1)"))
+		((string-match ")" current) (if prevp "1." "-"))
+		(t (error "This should not happen"))))
+     (and (looking-at "\\([ \t]*\\)\\S-+") (replace-match (concat "\\1" new)))
+     (org-fix-bullet-type)
+     (org-maybe-renumber-ordered-list))))
+
+(defun org-get-string-indentation (s)
+  "What indentation has S due to SPACE and TAB at the beginning of the string?"
+  (let ((n -1) (i 0) (w tab-width) c)
+    (catch 'exit
+      (while (< (setq n (1+ n)) (length s))
+	(setq c (aref s n))
+	(cond ((= c ?\ ) (setq i (1+ i)))
+	      ((= c ?\t) (setq i (* (/ (+ w i) w) w)))
+	      (t (throw 'exit t)))))
+    i))
+
+(defun org-renumber-ordered-list (arg)
+  "Renumber an ordered plain list.
+Cursor needs to be in the first line of an item, the line that starts
+with something like \"1.\" or \"2)\"."
+  (interactive "p")
+  (unless (and (org-at-item-p)
+	       (match-beginning 3))
+    (error "This is not an ordered list"))
+  (let ((line (org-current-line))
+	(col (current-column))
+	(ind (org-get-string-indentation
+	      (buffer-substring (point-at-bol) (match-beginning 3))))
+	;; (term (substring (match-string 3) -1))
+	ind1 (n (1- arg))
+	fmt bobp)
+    ;; find where this list begins
+    (org-beginning-of-item-list)
+    (setq bobp (bobp))
+    (looking-at "[ \t]*[0-9]+\\([.)]\\)")
+    (setq fmt (concat "%d" (match-string 1)))
+    (beginning-of-line 0)
+    ;; walk forward and replace these numbers
+    (catch 'exit
+      (while t
+	(catch 'next
+	  (if bobp (setq bobp nil) (beginning-of-line 2))
+	  (if (eobp) (throw 'exit nil))
+	  (if (looking-at "[ \t]*$") (throw 'next nil))
+	  (skip-chars-forward " \t") (setq ind1 (current-column))
+	  (if (> ind1 ind) (throw 'next t))
+	  (if (< ind1 ind) (throw 'exit t))
+	  (if (not (org-at-item-p)) (throw 'exit nil))
+	  (delete-region (match-beginning 2) (match-end 2))
+	  (goto-char (match-beginning 2))
+	  (insert (format fmt (setq n (1+ n)))))))
+    (goto-line line)
+    (org-move-to-column col)))
+
+(defun org-fix-bullet-type ()
+  "Make sure all items in this list have the same bullet as the firsst item."
+  (interactive)
+  (unless (org-at-item-p) (error "This is not a list"))
+  (let ((line (org-current-line))
+	(col (current-column))
+	(ind (current-indentation))
+	ind1 bullet)
+    ;; find where this list begins
+    (org-beginning-of-item-list)
+    (beginning-of-line 1)
+    ;; find out what the bullet type is
+    (looking-at "[ \t]*\\(\\S-+\\)")
+    (setq bullet (match-string 1))
+    ;; walk forward and replace these numbers
+    (beginning-of-line 0)
+    (catch 'exit
+      (while t
+	(catch 'next
+	  (beginning-of-line 2)
+	  (if (eobp) (throw 'exit nil))
+	  (if (looking-at "[ \t]*$") (throw 'next nil))
+	  (skip-chars-forward " \t") (setq ind1 (current-column))
+	  (if (> ind1 ind) (throw 'next t))
+	  (if (< ind1 ind) (throw 'exit t))
+	  (if (not (org-at-item-p)) (throw 'exit nil))
+	  (skip-chars-forward " \t")
+	  (looking-at "\\S-+")
+	  (replace-match bullet))))
+    (goto-line line)
+    (org-move-to-column col)
+    (if (string-match "[0-9]" bullet)
+	(org-renumber-ordered-list 1))))
+
+(defun org-beginning-of-item-list ()
+  "Go to the beginning of the current item list.
+I.e. to the first item in this list."
+  (interactive)
+  (org-beginning-of-item)
+  (let ((pos (point-at-bol))
+        (ind (org-get-indentation))
+	ind1)
+    ;; find where this list begins
+    (catch 'exit
+      (while t
+	(catch 'next
+	  (beginning-of-line 0)
+	  (if (looking-at "[ \t]*$")
+	      (throw (if (bobp) 'exit 'next) t))
+	  (skip-chars-forward " \t") (setq ind1 (current-column))
+	  (if (or (< ind1 ind)
+		  (and (= ind1 ind)
+		       (not (org-at-item-p)))
+		  (and (= (point-at-bol) (point-min))
+		       (setq pos (point-min))))
+	      (throw 'exit t)
+	    (when (org-at-item-p) (setq pos (point-at-bol)))))))
+    (goto-char pos)))
+
+
+(defun org-end-of-item-list ()
+  "Go to the end of the current item list.
+I.e. to the text after the last item."
+  (interactive)
+  (org-beginning-of-item)
+  (let ((pos (point-at-bol))
+        (ind (org-get-indentation))
+	ind1)
+    ;; find where this list begins
+    (catch 'exit
+      (while t
+	(catch 'next
+	  (beginning-of-line 2)
+	  (if (looking-at "[ \t]*$")
+	      (throw (if (eobp) 'exit 'next) t))
+	  (skip-chars-forward " \t") (setq ind1 (current-column))
+	  (if (or (< ind1 ind)
+		  (and (= ind1 ind)
+		       (not (org-at-item-p)))
+		  (eobp))
+	      (progn
+		(setq pos (point-at-bol))
+		(throw 'exit t))))))
+    (goto-char pos)))
+
+
+(defvar org-last-indent-begin-marker (make-marker))
+(defvar org-last-indent-end-marker (make-marker))
+
+(defun org-outdent-item (arg)
+  "Outdent a local list item."
+  (interactive "p")
+  (org-indent-item (- arg)))
+
+(defun org-indent-item (arg)
+  "Indent a local list item."
+  (interactive "p")
+  (unless (org-at-item-p)
+    (error "Not on an item"))
+  (save-excursion
+    (let (beg end ind ind1 tmp delta ind-down ind-up)
+      (if (memq last-command '(org-shiftmetaright org-shiftmetaleft))
+	  (setq beg org-last-indent-begin-marker
+		end org-last-indent-end-marker)
+	(org-beginning-of-item)
+	(setq beg (move-marker org-last-indent-begin-marker (point)))
+	(org-end-of-item)
+	(setq end (move-marker org-last-indent-end-marker (point))))
+      (goto-char beg)
+      (setq tmp (org-item-indent-positions)
+	    ind (car tmp)
+	    ind-down (nth 2 tmp)
+	    ind-up (nth 1 tmp)
+	    delta (if (> arg 0)
+		      (if ind-down (- ind-down ind) 2)
+		    (if ind-up (- ind-up ind) -2)))
+      (if (< (+ delta ind) 0) (error "Cannot outdent beyond margin"))
+      (while (< (point) end)
+	(beginning-of-line 1)
+	(skip-chars-forward " \t") (setq ind1 (current-column))
+	(delete-region (point-at-bol) (point))
+	(or (eolp) (org-indent-to-column (+ ind1 delta)))
+	(beginning-of-line 2))))
+  (org-fix-bullet-type)
+  (org-maybe-renumber-ordered-list-safe)
+  (save-excursion
+    (beginning-of-line 0)
+    (condition-case nil (org-beginning-of-item) (error nil))
+    (org-maybe-renumber-ordered-list-safe)))
+
+(defun org-item-indent-positions ()
+  "Return indentation for plain list items.
+This returns a list with three values:  The current indentation, the
+parent indentation and the indentation a child should habe.
+Assumes cursor in item line."
+  (let* ((bolpos (point-at-bol))
+	 (ind (org-get-indentation))
+	 ind-down ind-up pos)
+    (save-excursion
+      (org-beginning-of-item-list)
+      (skip-chars-backward "\n\r \t")
+      (when (org-in-item-p)
+	(org-beginning-of-item)
+	(setq ind-up (org-get-indentation))))
+    (setq pos (point))
+    (save-excursion
+      (cond
+       ((and (condition-case nil (progn (org-previous-item) t)
+	       (error nil))
+	     (or (forward-char 1) t)
+	     (re-search-forward "^\\([ \t]*\\([-+]\\|\\([0-9]+[.)]\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)" bolpos t))
+	(setq ind-down (org-get-indentation)))
+       ((and (goto-char pos)
+	     (org-at-item-p))
+	(goto-char (match-end 0))
+	(skip-chars-forward " \t")
+	(setq ind-down (current-column)))))
+    (list ind ind-up ind-down)))
+
+
+
+
+
+
+
+
+
+(defun org-list-parse-list (&optional delete)
+  "Parse the list at point and maybe DELETE it.
+Return a list containing first level items as strings and
+sublevels as a list of strings."
+  (let* ((item-beginning (org-list-item-beginning))
+         (start (car item-beginning))
+         (end (org-list-end (cdr item-beginning)))
+         output itemsep ltype)
+    (while (re-search-forward org-list-beginning-re end t)
+      (goto-char (match-beginning 3))
+      (save-match-data
+        (cond ((string-match "[0-9]" (match-string 2))
+               (setq itemsep "[0-9]+\\(?:\\.\\|)\\)"
+                     ltype 'ordered))
+              ((string-match "^.*::" (match-string 0))
+               (setq itemsep "[-+]" ltype 'descriptive))
+              (t (setq itemsep "[-+]" ltype 'unordered))))
+      (let* ((indent1 (match-string 1))
+	     (nextitem (save-excursion
+			 (save-match-data
+			   (or (and (re-search-forward
+				     (concat "^" indent1 itemsep " *?") end t)
+				    (match-beginning 0)) end))))
+	     (item (buffer-substring
+		    (point)
+		    (or (and (re-search-forward
+			      org-list-beginning-re end t)
+			     (goto-char (match-beginning 0)))
+			(goto-char end))))
+	     (nextindent (match-string 1))
+	     (item (org-trim item))
+	     (item (if (string-match "^\\[.+\\]" item)
+		       (replace-match "\\\\texttt{\\&}"
+				      t nil item) item)))
+	(push item output)
+	(when (> (length nextindent)
+		 (length indent1))
+	  (narrow-to-region (point) nextitem)
+	  (push (org-list-parse-list) output)
+	  (widen))))
+    (when delete (delete-region start end))
+    (setq output (nreverse output))
+    (push ltype output)))
+
+(defun org-list-item-beginning ()
+  "Find the beginning of the list item.
+Return a cons which car is the beginning position of the item and
+cdr is the indentation string."
+  (save-excursion
+    (if (not (or (looking-at org-list-beginning-re)
+		 (re-search-backward
+		  org-list-beginning-re nil t)))
+	(progn (goto-char (point-min)) (point))
+      (cons (match-beginning 0) (match-string 1)))))
+
+(defun org-list-end (indent)
+  "Return the position of the end of the list.
+INDENT is the indentation of the list."
+  (save-excursion
+    (catch 'exit
+      (while (or (looking-at org-list-beginning-re)
+		 (looking-at (concat "^" indent "[ \t]+\\|^$")))
+	(if (eq (point) (point-max))
+	    (throw 'exit (point-max)))
+	(forward-line 1))) (point)))
+
+(defun org-list-insert-radio-list ()
+  "Insert a radio list template appropriate for this major mode."
+  (interactive)
+  (let* ((e (assq major-mode org-list-radio-list-templates))
+	 (txt (nth 1 e))
+	 name pos)
+    (unless e (error "No radio list setup defined for %s" major-mode))
+    (setq name (read-string "List name: "))
+    (while (string-match "%n" txt)
+      (setq txt (replace-match name t t txt)))
+    (or (bolp) (insert "\n"))
+    (setq pos (point))
+    (insert txt)
+    (goto-char pos)))
+
+(defun org-list-send-list (&optional maybe)
+  "Send a tranformed version of this list to the receiver position.
+With argument MAYBE, fail quietly if no transformation is defined for
+this list."
+  (interactive)
+  (catch 'exit
+    (unless (org-at-item-p) (error "Not at a list"))
+    (save-excursion
+      (goto-char (car (org-list-item-beginning)))
+      (beginning-of-line 0)
+      (unless (looking-at "#\\+ORGLST: *SEND +\\([a-zA-Z0-9_]+\\) +\\([^ \t\r\n]+\\)\\( +.*\\)?")
+	(if maybe
+	    (throw 'exit nil)
+	  (error "Don't know how to transform this list"))))
+    (let* ((name (match-string 1))
+           (item-beginning (org-list-item-beginning))
+	   (transform (intern (match-string 2)))
+	   (txt (buffer-substring-no-properties
+                 (car item-beginning)
+		 (org-list-end (cdr item-beginning))))
+	   (list (org-list-parse-list))
+           beg)
+      (unless (fboundp transform)
+	(error "No such transformation function %s" transform))
+      (setq txt (funcall transform list))
+      ;; Find the insertion place
+      (save-excursion
+	(goto-char (point-min))
+	(unless (re-search-forward
+		 (concat "BEGIN RECEIVE ORGLST +" name "\\([ \t]\\|$\\)") nil t)
+	  (error "Don't know where to insert translated list"))
+	(goto-char (match-beginning 0))
+	(beginning-of-line 2)
+	(setq beg (point))
+	(unless (re-search-forward (concat "END RECEIVE ORGLST +" name) nil t)
+	  (error "Cannot find end of insertion region"))
+	(beginning-of-line 1)
+	(delete-region beg (point))
+	(goto-char beg)
+	(insert txt "\n"))
+      (message "List converted and installed at receiver location"))))
+
+(defun org-list-to-generic (list params)
+  "Convert a LIST parsed through `org-list-parse-list' to other formats.
+
+Valid parameters PARAMS are
+
+:ustart     String to start an unordered list
+:uend       String to end an unordered list
+
+:ostart     String to start an ordered list
+:oend       String to end an ordered list
+
+:dstart     String to start a descriptive list
+:dend       String to end a descriptive list
+:dtstart    String to start a descriptive term
+:dtend      String to end a descriptive term
+:ddstart    String to start a description
+:ddend      String to end a description
+
+:splice     When set to t, return only list body lines, don't wrap
+            them into :[u/o]start and :[u/o]end.  Default is nil.
+
+:istart     String to start a list item
+:iend       String to end a list item
+:isep       String to separate items
+:lsep       String to separate sublists"
+  (interactive)
+  (let* ((p params) sublist
+	 (splicep (plist-get p :splice))
+	 (ostart  (plist-get p :ostart))
+	 (oend  (plist-get p :oend))
+	 (ustart  (plist-get p :ustart))
+	 (uend  (plist-get p :uend))
+	 (dstart  (plist-get p :dstart))
+	 (dend  (plist-get p :dend))
+	 (dtstart  (plist-get p :dtstart))
+	 (dtend  (plist-get p :dtend))
+	 (ddstart  (plist-get p :ddstart))
+	 (ddend  (plist-get p :ddend))
+	 (istart  (plist-get p :istart))
+	 (iend  (plist-get p :iend))
+	 (isep  (plist-get p :isep))
+	 (lsep  (plist-get p :lsep)))
+    (let ((wrapper
+	   (cond ((eq (car list) 'ordered)
+		  (concat ostart "\n%s" oend "\n"))
+		 ((eq (car list) 'unordered)
+		  (concat ustart "\n%s" uend "\n"))
+		 ((eq (car list) 'descriptive)
+		  (concat dstart "\n%s" dend "\n"))))
+	  rtn term defstart defend)
+      (while (setq sublist (pop list))
+	(cond ((symbolp sublist) nil)
+	      ((stringp sublist)
+               (when (string-match "^\\(.*\\) ::" sublist)
+                 (setq term (org-trim (format (concat dtstart "%s" dtend)
+                                              (match-string 1 sublist))))
+                 (setq sublist (substring sublist (1+ (length term)))))
+               (setq rtn (concat rtn istart term ddstart
+                                 sublist ddend iend isep)))
+              (t (setq rtn (concat rtn   ;; previous list
+                                   lsep  ;; list separator
+                                   (org-list-to-generic sublist p)
+                                   lsep  ;; list separator
+                                   )))))
+      (format wrapper rtn))))
+
+(defun org-list-to-latex (list)
+  "Convert LIST into a LaTeX list."
+  (org-list-to-generic
+   list '(:splicep nil :ostart "\\begin{enumerate}" :oend "\\end{enumerate}"
+                       :ustart "\\begin{itemize}" :uend "\\end{itemize}"
+                       :dstart "\\begin{description}" :dend "\\end{description}"
+                       :dtstart "[" :dtend "]"
+                       :ddstart "" :ddend ""
+                       :istart "\\item " :iend ""
+                       :isep "\n" :lsep "\n")))
+
+(defun org-list-to-html (list)
+  "Convert LIST into a HTML list."
+  (org-list-to-generic
+   list '(:splicep nil :ostart "<ol>" :oend "</ol>"
+                       :ustart "<ul>" :uend "</ul>"
+                       :dstart "<dl>" :dend "</dl>"
+                       :dtstart "<dt>" :dtend "</dt>"
+                       :ddstart "<dd>" :ddend "</dd>"
+                       :istart "<li>" :iend "</li>"
+                       :isep "\n" :lsep "\n")))
+
+(defun org-list-to-texinfo (list)
+  "Convert LIST into a Texinfo list."
+  (org-list-to-generic
+   list '(:splicep nil :ostart "@itemize @minus" :oend "@end itemize"
+                       :ustart "@enumerate" :uend "@end enumerate"
+                       :dstart "@table" :dend "@end table"
+                       :dtstart "@item " :dtend "\n"
+                       :ddstart "" :ddend ""
+                       :istart "@item\n" :iend ""
+                       :isep "\n" :lsep "\n")))
+
+(provide 'org-list)
+
+;;; org-list.el ends here

+ 37 - 763
lisp/org.el

@@ -86,6 +86,7 @@
 (require 'org-macs)
 (require 'org-compat)
 (require 'org-faces)
+(require 'org-list)
 
 ;;;; Customization variables
 
@@ -761,61 +762,6 @@ as possible."
   :group 'org-sparse-trees
   :type 'hook)
 
-(defgroup org-plain-lists nil
-  "Options concerning plain lists in Org-mode."
-  :tag "Org Plain lists"
-  :group 'org-structure)
-
-(defcustom org-cycle-include-plain-lists nil
-  "Non-nil means, include plain lists into visibility cycling.
-This means that during cycling, plain list items will *temporarily* be
-interpreted as outline headlines with a level given by 1000+i where i is the
-indentation of the bullet.  In all other operations, plain list items are
-not seen as headlines.  For example, you cannot assign a TODO keyword to
-such an item."
-  :group 'org-plain-lists
-  :type 'boolean)
-
-(defcustom org-plain-list-ordered-item-terminator t
-  "The character that makes a line with leading number an ordered list item.
-Valid values are ?. and ?\).  To get both terminators, use t.  While
-?. may look nicer, it creates the danger that a line with leading
-number may be incorrectly interpreted as an item.  ?\) therefore is
-the safe choice."
-  :group 'org-plain-lists
-  :type '(choice (const :tag "dot like in \"2.\"" ?.)
-		 (const :tag "paren like in \"2)\"" ?\))
-		 (const :tab "both" t)))
-
-(defcustom org-empty-line-terminates-plain-lists nil
-  "Non-nil means, an empty line ends all plain list levels.
-When nil, empty lines are part of the preceeding item."
-  :group 'org-plain-lists
-  :type 'boolean)
-
-(defcustom org-auto-renumber-ordered-lists t
-  "Non-nil means, automatically renumber ordered plain lists.
-Renumbering happens when the sequence have been changed with
-\\[org-shiftmetaup] or \\[org-shiftmetadown].  After other editing commands,
-use \\[org-ctrl-c-ctrl-c] to trigger renumbering."
-  :group 'org-plain-lists
-  :type 'boolean)
-
-(defcustom org-provide-checkbox-statistics t
-  "Non-nil means, update checkbox statistics after insert and toggle.
-When this is set, checkbox statistics is updated each time you either insert
-a new checkbox with \\[org-insert-todo-heading] or toggle a checkbox
-with \\[org-ctrl-c-ctrl-c\\]."
-  :group 'org-plain-lists
-  :type 'boolean)
-
-(defcustom org-description-max-indent 20
-  "Maximum indentation for the second line of a description list.
-When the indentation would be larger than this, it will become
-5 characters instead."
-  :group 'org-plain-lists
-  :type 'integer)
-
 (defgroup org-imenu-and-speedbar nil
   "Options concerning imenu and speedbar in Org-mode."
   :tag "Org Imenu and Speedbar"
@@ -5660,714 +5606,6 @@ the language, a switch telling of the content should be in a single line."
   (kill-buffer (current-buffer))
   (and (org-mode-p) (org-restart-font-lock)))
 
-;;;; Plain list items, including checkboxes
-
-;;; Plain list items
-
-(defun org-at-item-p ()
-  "Is point in a line starting a hand-formatted item?"
-  (let ((llt org-plain-list-ordered-item-terminator))
-    (save-excursion
-      (goto-char (point-at-bol))
-      (looking-at
-       (cond
-	((eq llt t)  "\\([ \t]*\\([-+]\\|\\([0-9]+[.)]\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)")
-	((= llt ?.)  "\\([ \t]*\\([-+]\\|\\([0-9]+\\.\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)")
-	((= llt ?\)) "\\([ \t]*\\([-+]\\|\\([0-9]+))\\)\\|[ \t]+\\*\\)\\( \\|$\\)")
-	(t (error "Invalid value of `org-plain-list-ordered-item-terminator'")))))))
-
-(defun org-in-item-p ()
-  "It the cursor inside a plain list item.
-Does not have to be the first line."
-  (save-excursion
-    (condition-case nil
-	(progn
-	  (org-beginning-of-item)
-	  (org-at-item-p)
-	  t)
-      (error nil))))
-
-(defun org-insert-item (&optional checkbox)
-  "Insert a new item at the current level.
-Return t when things worked, nil when we are not in an item."
-  (when (save-excursion
-	  (condition-case nil
-	      (progn
-		(org-beginning-of-item)
-		(org-at-item-p)
-		(if (org-invisible-p) (error "Invisible item"))
-		t)
-	    (error nil)))
-    (let* ((bul (match-string 0))
-	   (descp (save-excursion (goto-char (match-beginning 0))
-				  (beginning-of-line 1)
-				  (save-match-data
-				    (looking-at "[ \t]*.*? ::"))))
-	   (eow (save-excursion (beginning-of-line 1) (looking-at "[ \t]*")
-				(match-end 0)))
-	   (blank (cdr (assq 'plain-list-item org-blank-before-new-entry)))
-	   pos)
-      (if descp (setq checkbox nil))
-      (cond
-       ((and (org-at-item-p) (<= (point) eow))
-	;; before the bullet
-	(beginning-of-line 1)
-	(open-line (if blank 2 1)))
-       ((<= (point) eow)
-	(beginning-of-line 1))
-       (t
-	(unless (org-get-alist-option org-M-RET-may-split-line 'item)
-	  (end-of-line 1)
-	  (delete-horizontal-space))
-	(newline (if blank 2 1))))
-      (insert bul
-	      (if checkbox "[ ]" "")
-	      (if descp (concat (if checkbox " " "")
-				(read-string "Term: ") " :: ") ""))
-      (just-one-space)
-      (setq pos (point))
-      (end-of-line 1)
-      (unless (= (point) pos) (just-one-space) (backward-delete-char 1)))
-    (org-maybe-renumber-ordered-list)
-    (and checkbox (org-update-checkbox-count-maybe))
-    t))
-
-;;; Checkboxes
-
-(defun org-at-item-checkbox-p ()
-  "Is point at a line starting a plain-list item with a checklet?"
-  (and (org-at-item-p)
-       (save-excursion
-	 (goto-char (match-end 0))
-	 (skip-chars-forward " \t")
-	 (looking-at "\\[[- X]\\]"))))
-
-(defun org-toggle-checkbox (&optional arg)
-  "Toggle the checkbox in the current line."
-  (interactive "P")
-  (catch 'exit
-    (let (beg end status (firstnew 'unknown))
-      (cond
-       ((org-region-active-p)
-	(setq beg (region-beginning) end (region-end)))
-       ((org-on-heading-p)
-	(setq beg (point) end (save-excursion (outline-next-heading) (point))))
-       ((org-at-item-checkbox-p)
-	(let ((pos (point)))
-	  (replace-match
-	   (cond (arg "[-]")
-		 ((member (match-string 0) '("[ ]" "[-]")) "[X]")
-		 (t "[ ]"))
-	   t t)
-	  (goto-char pos))
-	(throw 'exit t))
-       (t (error "Not at a checkbox or heading, and no active region")))
-      (save-excursion
-	(goto-char beg)
-	(while (< (point) end)
-	  (when (org-at-item-checkbox-p)
-	    (setq status (equal (match-string 0) "[X]"))
-	    (when (eq firstnew 'unknown)
-	      (setq firstnew (not status)))
-	    (replace-match
-	     (if (if arg (not status) firstnew) "[X]" "[ ]") t t))
-	  (beginning-of-line 2)))))
-  (org-update-checkbox-count-maybe))
-
-(defun org-update-checkbox-count-maybe ()
-  "Update checkbox statistics unless turned off by user."
-  (when org-provide-checkbox-statistics
-    (org-update-checkbox-count)))
-
-(defun org-update-checkbox-count (&optional all)
- "Update the checkbox statistics in the current section.
-This will find all statistic cookies like [57%] and [6/12] and update them
-with the current numbers.  With optional prefix argument ALL, do this for
-the whole buffer."
- (interactive "P")
- (save-excursion
-   (let* ((buffer-invisibility-spec (org-inhibit-invisibility)) ; Emacs 21
-	  (beg (condition-case nil
-		   (progn (outline-back-to-heading) (point))
-		 (error (point-min))))
-	  (end (move-marker (make-marker)
-			    (progn (outline-next-heading) (point))))
-	  (re "\\(\\(\\[[0-9]*%\\]\\)\\|\\(\\[[0-9]*/[0-9]*\\]\\)\\)")
-	  (re-box "^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +\\(\\[[- X]\\]\\)")
-	  (re-find (concat re "\\|" re-box))
-	  beg-cookie end-cookie is-percent c-on c-off lim
-          eline curr-ind next-ind continue-from startsearch
-          (cstat 0)
-          )
-     (when all
-       (goto-char (point-min))
-       (outline-next-heading)
-       (setq beg (point) end (point-max)))
-     (goto-char end)
-     ;; find each statistic cookie
-     (while (re-search-backward re-find beg t)
-       (setq beg-cookie (match-beginning 1)
-             end-cookie (match-end 1)
-	     cstat (+ cstat (if end-cookie 1 0))
-	     startsearch (point-at-eol)
-	     continue-from (point-at-bol)
-             is-percent (match-beginning 2)
-	     lim (cond
-		  ((org-on-heading-p) (outline-next-heading) (point))
-		  ((org-at-item-p) (org-end-of-item) (point))
-		  (t nil))
-             c-on 0
-             c-off 0)
-       (when lim
-         ;; find first checkbox for this cookie and gather
-         ;; statistics from all that are at this indentation level
-         (goto-char startsearch)
-         (if (re-search-forward re-box lim t)
-             (progn
-               (org-beginning-of-item)
-               (setq curr-ind (org-get-indentation))
-               (setq next-ind curr-ind)
-               (while (and (bolp) (org-at-item-p) (= curr-ind next-ind))
-                 (save-excursion (end-of-line) (setq eline (point)))
-                 (if (re-search-forward re-box eline t)
-		     (if (member (match-string 2) '("[ ]" "[-]"))
-			 (setq c-off (1+ c-off))
-                       (setq c-on (1+ c-on))
-                       )
-                   )
-                 (org-end-of-item)
-                 (setq next-ind (org-get-indentation))
-                 )))
-	 (goto-char continue-from)
-         ;; update cookie
-	 (when end-cookie
-	   (delete-region beg-cookie end-cookie)
-	   (goto-char beg-cookie)
-	   (insert
-	    (if is-percent
-		(format "[%d%%]" (/ (* 100 c-on) (max 1 (+ c-on c-off))))
-	      (format "[%d/%d]" c-on (+ c-on c-off)))))
-         ;; update items checkbox if it has one
-         (when (org-at-item-p)
-           (org-beginning-of-item)
-           (when (and (> (+ c-on c-off) 0)
-		      (re-search-forward re-box (point-at-eol) t))
-             (setq beg-cookie (match-beginning 2)
-                   end-cookie (match-end       2))
-             (delete-region beg-cookie end-cookie)
-             (goto-char beg-cookie)
-             (cond ((= c-off 0) (insert "[X]"))
-                   ((= c-on  0) (insert "[ ]"))
-                   (t           (insert "[-]")))
-             )))
-       (goto-char continue-from))
-     (when (interactive-p)
-       (message "Checkbox satistics updated %s (%d places)"
-		(if all "in entire file" "in current outline entry") cstat)))))
-
-(defun org-get-checkbox-statistics-face ()
-  "Select the face for checkbox statistics.
-The face will be `org-done' when all relevant boxes are checked.  Otherwise
-it will be `org-todo'."
-  (if (match-end 1)
-      (if (equal (match-string 1) "100%") 'org-done 'org-todo)
-    (if (and (> (match-end 2) (match-beginning 2))
-	     (equal (match-string 2) (match-string 3)))
-	'org-done
-      'org-todo)))
-
-(defun org-get-indentation (&optional line)
-  "Get the indentation of the current line, interpreting tabs.
-When LINE is given, assume it represents a line and compute its indentation."
-  (if line
-      (if (string-match "^ *" (org-remove-tabs line))
-	  (match-end 0))
-    (save-excursion
-      (beginning-of-line 1)
-      (skip-chars-forward " \t")
-      (current-column))))
-
-(defun org-remove-tabs (s &optional width)
-  "Replace tabulators in S with spaces.
-Assumes that s is a single line, starting in column 0."
-  (setq width (or width tab-width))
-  (while (string-match "\t" s)
-    (setq s (replace-match
-	     (make-string
-	      (- (* width (/ (+ (match-beginning 0) width) width))
-		 (match-beginning 0)) ?\ )
-	     t t s)))
-  s)
-
-(defun org-fix-indentation (line ind)
-  "Fix indentation in LINE.
-IND is a cons cell with target and minimum indentation.
-If the current indenation in LINE is smaller than the minimum,
-leave it alone.  If it is larger than ind, set it to the target."
-  (let* ((l (org-remove-tabs line))
-	 (i (org-get-indentation l))
-	 (i1 (car ind)) (i2 (cdr ind)))
-    (if (>= i i2) (setq l (substring line i2)))
-    (if (> i1 0)
-	(concat (make-string i1 ?\ ) l)
-      l)))
-
-(defun org-beginning-of-item ()
-  "Go to the beginning of the current hand-formatted item.
-If the cursor is not in an item, throw an error."
-  (interactive)
-  (let ((pos (point))
-	(limit (save-excursion
-		 (condition-case nil
-		     (progn
-		       (org-back-to-heading)
-		       (beginning-of-line 2) (point))
-		   (error (point-min)))))
-	(ind-empty (if org-empty-line-terminates-plain-lists 0 10000))
-	ind ind1)
-    (if (org-at-item-p)
-	(beginning-of-line 1)
-      (beginning-of-line 1)
-      (skip-chars-forward " \t")
-      (setq ind (current-column))
-      (if (catch 'exit
-	    (while t
-	      (beginning-of-line 0)
-	      (if (or (bobp) (< (point) limit)) (throw 'exit nil))
-
-	      (if (looking-at "[ \t]*$")
-		  (setq ind1 ind-empty)
-		(skip-chars-forward " \t")
-		(setq ind1 (current-column)))
-	      (if (< ind1 ind)
-		  (progn (beginning-of-line 1) (throw 'exit (org-at-item-p))))))
-	  nil
-	(goto-char pos)
-	(error "Not in an item")))))
-
-(defun org-end-of-item ()
-  "Go to the end of the current hand-formatted item.
-If the cursor is not in an item, throw an error."
-  (interactive)
-  (let* ((pos (point))
-	 ind1
-	 (ind-empty (if org-empty-line-terminates-plain-lists 0 10000))
-	 (limit (save-excursion (outline-next-heading) (point)))
-	 (ind (save-excursion
-		(org-beginning-of-item)
-		(skip-chars-forward " \t")
-		(current-column)))
-	 (end (catch 'exit
-		(while t
-		  (beginning-of-line 2)
-		  (if (eobp) (throw 'exit (point)))
-		  (if (>= (point) limit) (throw 'exit (point-at-bol)))
-		  (if (looking-at "[ \t]*$")
-		      (setq ind1 ind-empty)
-		    (skip-chars-forward " \t")
-		    (setq ind1 (current-column)))
-		  (if (<= ind1 ind)
-		      (throw 'exit (point-at-bol)))))))
-    (if end
-	(goto-char end)
-      (goto-char pos)
-      (error "Not in an item"))))
-
-(defun org-next-item ()
-  "Move to the beginning of the next item in the current plain list.
-Error if not at a plain list, or if this is the last item in the list."
-  (interactive)
-  (let (ind ind1 (pos (point)))
-    (org-beginning-of-item)
-    (setq ind (org-get-indentation))
-    (org-end-of-item)
-    (setq ind1 (org-get-indentation))
-    (unless (and (org-at-item-p) (= ind ind1))
-      (goto-char pos)
-      (error "On last item"))))
-
-(defun org-previous-item ()
-  "Move to the beginning of the previous item in the current plain list.
-Error if not at a plain list, or if this is the first item in the list."
-  (interactive)
-  (let (beg ind ind1 (pos (point)))
-    (org-beginning-of-item)
-    (setq beg (point))
-    (setq ind (org-get-indentation))
-    (goto-char beg)
-    (catch 'exit
-      (while t
-	(beginning-of-line 0)
-	(if (looking-at "[ \t]*$")
-	    nil
-	  (if (<= (setq ind1 (org-get-indentation)) ind)
-	      (throw 'exit t)))))
-    (condition-case nil
-	(if (or (not (org-at-item-p))
-		(< ind1 (1- ind)))
-	    (error "")
-	  (org-beginning-of-item))
-      (error (goto-char pos)
-	     (error "On first item")))))
-
-(defun org-first-list-item-p ()
-  "Is this heading the item in a plain list?"
-  (unless (org-at-item-p)
-    (error "Not at a plain list item"))
-  (org-beginning-of-item)
-  (= (point) (save-excursion (org-beginning-of-item-list))))
-
-(defun org-move-item-down ()
-  "Move the plain list item at point down, i.e. swap with following item.
-Subitems (items with larger indentation) are considered part of the item,
-so this really moves item trees."
-  (interactive)
-  (let (beg beg0 end end0 ind ind1 (pos (point)) txt ne-end ne-beg)
-    (org-beginning-of-item)
-    (setq beg0 (point))
-    (save-excursion
-      (setq ne-beg (org-back-over-empty-lines))
-      (setq beg (point)))
-    (goto-char beg0)
-    (setq ind (org-get-indentation))
-    (org-end-of-item)
-    (setq end0 (point))
-    (setq ind1 (org-get-indentation))
-    (setq ne-end (org-back-over-empty-lines))
-    (setq end (point))
-    (goto-char beg0)
-    (when (and (org-first-list-item-p) (< ne-end ne-beg))
-      ;; include less whitespace
-      (save-excursion
-	(goto-char beg)
-	(forward-line (- ne-beg ne-end))
-	(setq beg (point))))
-    (goto-char end0)
-    (if (and (org-at-item-p) (= ind ind1))
-	(progn
-	  (org-end-of-item)
-	  (org-back-over-empty-lines)
-	  (setq txt (buffer-substring beg end))
-	  (save-excursion
-	    (delete-region beg end))
-	  (setq pos (point))
-	  (insert txt)
-	  (goto-char pos) (org-skip-whitespace)
-	  (org-maybe-renumber-ordered-list))
-      (goto-char pos)
-      (error "Cannot move this item further down"))))
-
-(defun org-move-item-up (arg)
-  "Move the plain list item at point up, i.e. swap with previous item.
-Subitems (items with larger indentation) are considered part of the item,
-so this really moves item trees."
-  (interactive "p")
-  (let (beg beg0 end ind ind1 (pos (point)) txt
-	    ne-beg ne-ins ins-end)
-    (org-beginning-of-item)
-    (setq beg0 (point))
-    (setq ind (org-get-indentation))
-    (save-excursion
-      (setq ne-beg (org-back-over-empty-lines))
-      (setq beg (point)))
-    (goto-char beg0)
-    (org-end-of-item)
-    (org-back-over-empty-lines)
-    (setq end (point))
-    (goto-char beg0)
-    (catch 'exit
-      (while t
-	(beginning-of-line 0)
-	(if (looking-at "[ \t]*$")
-	    (if org-empty-line-terminates-plain-lists
-		(progn
-		  (goto-char pos)
-		  (error "Cannot move this item further up"))
-	      nil)
-	  (if (<= (setq ind1 (org-get-indentation)) ind)
-	      (throw 'exit t)))))
-    (condition-case nil
-	(org-beginning-of-item)
-      (error (goto-char beg0)
-	     (error "Cannot move this item further up")))
-    (setq ind1 (org-get-indentation))
-    (if (and (org-at-item-p) (= ind ind1))
-	(progn
-	  (setq ne-ins (org-back-over-empty-lines))
-	  (setq txt (buffer-substring beg end))
-	  (save-excursion
-	    (delete-region beg end))
-	  (setq pos (point))
-	  (insert txt)
-	  (setq ins-end (point))
-	  (goto-char pos) (org-skip-whitespace)
-
-	  (when (and (org-first-list-item-p) (> ne-ins ne-beg))
-	    ;; Move whitespace back to beginning
-	    (save-excursion
-	      (goto-char ins-end)
-	      (let ((kill-whole-line t))
-		(kill-line (- ne-ins ne-beg)) (point)))
-	    (insert (make-string (- ne-ins ne-beg) ?\n)))
-
-	  (org-maybe-renumber-ordered-list))
-      (goto-char pos)
-      (error "Cannot move this item further up"))))
-
-(defun org-maybe-renumber-ordered-list ()
-  "Renumber the ordered list at point if setup allows it.
-This tests the user option `org-auto-renumber-ordered-lists' before
-doing the renumbering."
-  (interactive)
-  (when (and org-auto-renumber-ordered-lists
-	     (org-at-item-p))
-    (if (match-beginning 3)
-	(org-renumber-ordered-list 1)
-      (org-fix-bullet-type))))
-
-(defun org-maybe-renumber-ordered-list-safe ()
-  (condition-case nil
-      (save-excursion
-	(org-maybe-renumber-ordered-list))
-    (error nil)))
-
-(defun org-cycle-list-bullet (&optional which)
-  "Cycle through the different itemize/enumerate bullets.
-This cycle the entire list level through the sequence:
-
-   `-'  ->  `+'  ->  `*'  ->  `1.'  ->  `1)'
-
-If WHICH is a string, use that as the new bullet.  If WHICH is an integer,
-0 meand `-', 1 means `+' etc."
-  (interactive "P")
-  (org-preserve-lc
-   (org-beginning-of-item-list)
-   (org-at-item-p)
-   (beginning-of-line 1)
-   (let ((current (match-string 0))
-	 (prevp (eq which 'previous))
-	 new)
-     (setq new (cond
-		((and (numberp which)
-		      (nth (1- which) '("-" "+" "*" "1." "1)"))))
-		((string-match "-" current) (if prevp "1)" "+"))
-		((string-match "\\+" current)
-		 (if prevp "-" (if (looking-at "\\S-") "1." "*")))
-		((string-match "\\*" current) (if prevp "+" "1."))
-		((string-match "\\." current) (if prevp "*" "1)"))
-		((string-match ")" current) (if prevp "1." "-"))
-		(t (error "This should not happen"))))
-     (and (looking-at "\\([ \t]*\\)\\S-+") (replace-match (concat "\\1" new)))
-     (org-fix-bullet-type)
-     (org-maybe-renumber-ordered-list))))
-
-(defun org-get-string-indentation (s)
-  "What indentation has S due to SPACE and TAB at the beginning of the string?"
-  (let ((n -1) (i 0) (w tab-width) c)
-    (catch 'exit
-      (while (< (setq n (1+ n)) (length s))
-	(setq c (aref s n))
-	(cond ((= c ?\ ) (setq i (1+ i)))
-	      ((= c ?\t) (setq i (* (/ (+ w i) w) w)))
-	      (t (throw 'exit t)))))
-    i))
-
-(defun org-renumber-ordered-list (arg)
-  "Renumber an ordered plain list.
-Cursor needs to be in the first line of an item, the line that starts
-with something like \"1.\" or \"2)\"."
-  (interactive "p")
-  (unless (and (org-at-item-p)
-	       (match-beginning 3))
-    (error "This is not an ordered list"))
-  (let ((line (org-current-line))
-	(col (current-column))
-	(ind (org-get-string-indentation
-	      (buffer-substring (point-at-bol) (match-beginning 3))))
-	;; (term (substring (match-string 3) -1))
-	ind1 (n (1- arg))
-	fmt bobp)
-    ;; find where this list begins
-    (org-beginning-of-item-list)
-    (setq bobp (bobp))
-    (looking-at "[ \t]*[0-9]+\\([.)]\\)")
-    (setq fmt (concat "%d" (match-string 1)))
-    (beginning-of-line 0)
-    ;; walk forward and replace these numbers
-    (catch 'exit
-      (while t
-	(catch 'next
-	  (if bobp (setq bobp nil) (beginning-of-line 2))
-	  (if (eobp) (throw 'exit nil))
-	  (if (looking-at "[ \t]*$") (throw 'next nil))
-	  (skip-chars-forward " \t") (setq ind1 (current-column))
-	  (if (> ind1 ind) (throw 'next t))
-	  (if (< ind1 ind) (throw 'exit t))
-	  (if (not (org-at-item-p)) (throw 'exit nil))
-	  (delete-region (match-beginning 2) (match-end 2))
-	  (goto-char (match-beginning 2))
-	  (insert (format fmt (setq n (1+ n)))))))
-    (goto-line line)
-    (org-move-to-column col)))
-
-(defun org-fix-bullet-type ()
-  "Make sure all items in this list have the same bullet as the firsst item."
-  (interactive)
-  (unless (org-at-item-p) (error "This is not a list"))
-  (let ((line (org-current-line))
-	(col (current-column))
-	(ind (current-indentation))
-	ind1 bullet)
-    ;; find where this list begins
-    (org-beginning-of-item-list)
-    (beginning-of-line 1)
-    ;; find out what the bullet type is
-    (looking-at "[ \t]*\\(\\S-+\\)")
-    (setq bullet (match-string 1))
-    ;; walk forward and replace these numbers
-    (beginning-of-line 0)
-    (catch 'exit
-      (while t
-	(catch 'next
-	  (beginning-of-line 2)
-	  (if (eobp) (throw 'exit nil))
-	  (if (looking-at "[ \t]*$") (throw 'next nil))
-	  (skip-chars-forward " \t") (setq ind1 (current-column))
-	  (if (> ind1 ind) (throw 'next t))
-	  (if (< ind1 ind) (throw 'exit t))
-	  (if (not (org-at-item-p)) (throw 'exit nil))
-	  (skip-chars-forward " \t")
-	  (looking-at "\\S-+")
-	  (replace-match bullet))))
-    (goto-line line)
-    (org-move-to-column col)
-    (if (string-match "[0-9]" bullet)
-	(org-renumber-ordered-list 1))))
-
-(defun org-beginning-of-item-list ()
-  "Go to the beginning of the current item list.
-I.e. to the first item in this list."
-  (interactive)
-  (org-beginning-of-item)
-  (let ((pos (point-at-bol))
-        (ind (org-get-indentation))
-	ind1)
-    ;; find where this list begins
-    (catch 'exit
-      (while t
-	(catch 'next
-	  (beginning-of-line 0)
-	  (if (looking-at "[ \t]*$")
-	      (throw (if (bobp) 'exit 'next) t))
-	  (skip-chars-forward " \t") (setq ind1 (current-column))
-	  (if (or (< ind1 ind)
-		  (and (= ind1 ind)
-		       (not (org-at-item-p)))
-		  (and (= (point-at-bol) (point-min))
-		       (setq pos (point-min))))
-	      (throw 'exit t)
-	    (when (org-at-item-p) (setq pos (point-at-bol)))))))
-    (goto-char pos)))
-
-
-(defun org-end-of-item-list ()
-  "Go to the end of the current item list.
-I.e. to the text after the last item."
-  (interactive)
-  (org-beginning-of-item)
-  (let ((pos (point-at-bol))
-        (ind (org-get-indentation))
-	ind1)
-    ;; find where this list begins
-    (catch 'exit
-      (while t
-	(catch 'next
-	  (beginning-of-line 2)
-	  (if (looking-at "[ \t]*$")
-	      (throw (if (eobp) 'exit 'next) t))
-	  (skip-chars-forward " \t") (setq ind1 (current-column))
-	  (if (or (< ind1 ind)
-		  (and (= ind1 ind)
-		       (not (org-at-item-p)))
-		  (eobp))
-	      (progn
-		(setq pos (point-at-bol))
-		(throw 'exit t))))))
-    (goto-char pos)))
-
-
-(defvar org-last-indent-begin-marker (make-marker))
-(defvar org-last-indent-end-marker (make-marker))
-
-(defun org-outdent-item (arg)
-  "Outdent a local list item."
-  (interactive "p")
-  (org-indent-item (- arg)))
-
-(defun org-indent-item (arg)
-  "Indent a local list item."
-  (interactive "p")
-  (unless (org-at-item-p)
-    (error "Not on an item"))
-  (save-excursion
-    (let (beg end ind ind1 tmp delta ind-down ind-up)
-      (if (memq last-command '(org-shiftmetaright org-shiftmetaleft))
-	  (setq beg org-last-indent-begin-marker
-		end org-last-indent-end-marker)
-	(org-beginning-of-item)
-	(setq beg (move-marker org-last-indent-begin-marker (point)))
-	(org-end-of-item)
-	(setq end (move-marker org-last-indent-end-marker (point))))
-      (goto-char beg)
-      (setq tmp (org-item-indent-positions)
-	    ind (car tmp)
-	    ind-down (nth 2 tmp)
-	    ind-up (nth 1 tmp)
-	    delta (if (> arg 0)
-		      (if ind-down (- ind-down ind) 2)
-		    (if ind-up (- ind-up ind) -2)))
-      (if (< (+ delta ind) 0) (error "Cannot outdent beyond margin"))
-      (while (< (point) end)
-	(beginning-of-line 1)
-	(skip-chars-forward " \t") (setq ind1 (current-column))
-	(delete-region (point-at-bol) (point))
-	(or (eolp) (org-indent-to-column (+ ind1 delta)))
-	(beginning-of-line 2))))
-  (org-fix-bullet-type)
-  (org-maybe-renumber-ordered-list-safe)
-  (save-excursion
-    (beginning-of-line 0)
-    (condition-case nil (org-beginning-of-item) (error nil))
-    (org-maybe-renumber-ordered-list-safe)))
-
-(defun org-item-indent-positions ()
-  "Return indentation for plain list items.
-This returns a list with three values:  The current indentation, the
-parent indentation and the indentation a child should habe.
-Assumes cursor in item line."
-  (let* ((bolpos (point-at-bol))
-	 (ind (org-get-indentation))
-	 ind-down ind-up pos)
-    (save-excursion
-      (org-beginning-of-item-list)
-      (skip-chars-backward "\n\r \t")
-      (when (org-in-item-p)
-	(org-beginning-of-item)
-	(setq ind-up (org-get-indentation))))
-    (setq pos (point))
-    (save-excursion
-      (cond
-       ((and (condition-case nil (progn (org-previous-item) t)
-	       (error nil))
-	     (or (forward-char 1) t)
-	     (re-search-forward "^\\([ \t]*\\([-+]\\|\\([0-9]+[.)]\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)" bolpos t))
-	(setq ind-down (org-get-indentation)))
-       ((and (goto-char pos)
-	     (org-at-item-p))
-	(goto-char (match-end 0))
-	(skip-chars-forward " \t")
-	(setq ind-down (current-column)))))
-    (list ind ind-up ind-down)))
 
 ;;; The orgstruct minor mode
 
@@ -13771,6 +13009,42 @@ upon the next fontification round."
       (setq l (- l (get-text-property b 'org-dwidth-n s))))
     l))
 
+(defun org-get-indentation (&optional line)
+  "Get the indentation of the current line, interpreting tabs.
+When LINE is given, assume it represents a line and compute its indentation."
+  (if line
+      (if (string-match "^ *" (org-remove-tabs line))
+	  (match-end 0))
+    (save-excursion
+      (beginning-of-line 1)
+      (skip-chars-forward " \t")
+      (current-column))))
+
+(defun org-remove-tabs (s &optional width)
+  "Replace tabulators in S with spaces.
+Assumes that s is a single line, starting in column 0."
+  (setq width (or width tab-width))
+  (while (string-match "\t" s)
+    (setq s (replace-match
+	     (make-string
+	      (- (* width (/ (+ (match-beginning 0) width) width))
+		 (match-beginning 0)) ?\ )
+	     t t s)))
+  s)
+
+(defun org-fix-indentation (line ind)
+  "Fix indentation in LINE.
+IND is a cons cell with target and minimum indentation.
+If the current indenation in LINE is smaller than the minimum,
+leave it alone.  If it is larger than ind, set it to the target."
+  (let* ((l (org-remove-tabs line))
+	 (i (org-get-indentation l))
+	 (i1 (car ind)) (i2 (cdr ind)))
+    (if (>= i i2) (setq l (substring line i2)))
+    (if (> i1 0)
+	(concat (make-string i1 ?\ ) l)
+      l)))
+
 (defun org-base-buffer (buffer)
   "Return the base buffer of BUFFER, if it has one.  Else return the buffer."
   (if (not buffer)