]> code.delx.au - gnu-emacs/blobdiff - lisp/org/org-list.el
Merge changes from emacs-23 branch.
[gnu-emacs] / lisp / org / org-list.el
index 84eb78c13034ac1ca376b2a71c1410e18e7e7da6..19ba1a963955b89a52da5224ec459d51d53d2eba 100644 (file)
@@ -7,7 +7,7 @@
 ;;        Bastien Guerry <bzg AT altern DOT org>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: http://orgmode.org
-;; Version: 6.35i
+;; Version: 7.01
 ;;
 ;; This file is part of GNU Emacs.
 ;;
@@ -31,6 +31,8 @@
 
 ;;; Code:
 
+(eval-when-compile
+  (require 'cl))
 (require 'org-macs)
 (require 'org-compat)
 
@@ -49,7 +51,8 @@
 (declare-function org-get-indentation "org" (&optional line))
 (declare-function org-timer-item "org-timer" (&optional arg))
 (declare-function org-combine-plists "org" (&rest plists))
-(declare-function org-entry-get "org" (pom property &optional inherit))
+(declare-function org-entry-get "org"
+                 (pom property &optional inherit literal-nil))
 (declare-function org-narrow-to-subtree "org" ())
 (declare-function org-show-subtree "org" ())
 
@@ -84,7 +87,29 @@ heading will be exposed in a children' view."
 (defcustom org-list-demote-modify-bullet nil
   "Default bullet type installed when demoting an item.
 This is an association list, for each bullet type, this alist will point
-to the bulled that should be used when this item is demoted."
+to the bullet that should be used when this item is demoted.
+For example,
+
+ (setq org-list-demote-modify-bullet
+       '((\"+\" . \"-\") (\"-\" . \"+\") (\"*\" . \"+\")))
+
+will make
+
+  + Movies
+    + Silence of the Lambs
+    + My Cousin Vinny
+  + Books
+    + The Hunt for Red October
+    + The Road to Omaha
+
+into
+
+  + Movies
+    - Silence of the Lambs
+    - My Cousin Vinny
+  + Books
+    - The Hunt for Red October
+    - The Road to Omaha"
   :group 'org-plain-lists
   :type '(repeat
          (cons
@@ -119,7 +144,7 @@ When a string, it will be used as a regular expression.      When the bullet
 type of a list is changed, the new bullet type will be matched against this
 regexp.         If it matches, there will be two spaces instead of one after
 the bullet in each item of he list."
-  :group 'org-plain-list
+  :group 'org-plain-lists
   :type '(choice
          (const :tag "never" nil)
          (regexp)))
@@ -171,19 +196,19 @@ When the indentation would be larger than this, it will become
 % 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
@@ -197,17 +222,25 @@ list, obtained by prompting the user."
 
 ;;; Plain list items
 
+(defun org-item-re (&optional general)
+  "Return the correct regular expression for plain lists.
+If GENERAL is non-nil, return the general regexp independent of the value
+of `org-plain-list-ordered-item-terminator'."
+  (cond
+   ((or general (eq org-plain-list-ordered-item-terminator t))
+    "\\([ \t]*\\([-+]\\|\\([0-9]+[.)]\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)")
+   ((= org-plain-list-ordered-item-terminator ?.)
+    "\\([ \t]*\\([-+]\\|\\([0-9]+\\.\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)")
+   ((= org-plain-list-ordered-item-terminator ?\))
+    "\\([ \t]*\\([-+]\\|\\([0-9]+)\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)")
+   (t (error "Invalid value of `org-plain-list-ordered-item-terminator'"))))
+
 (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'")))))))
+
+  (save-excursion
+    (goto-char (point-at-bol))
+    (looking-at (org-item-re))))
 
 (defun org-at-item-bullet-p ()
   "Is point at the bullet of a plain list item?"
@@ -216,7 +249,7 @@ list, obtained by prompting the user."
        (< (point) (match-end 0))))
 
 (defun org-in-item-p ()
-  "It the cursor inside a plain list item.
+  "Is the cursor inside a plain list item.
 Does not have to be the first line."
   (save-excursion
     (condition-case nil
@@ -590,6 +623,17 @@ If the cursor is not in an item, throw an error."
       (goto-char pos)
       (error "Not in an item"))))
 
+(defun org-end-of-item-text-before-children ()
+  "Move to the end of the item text, stops before the first child if any.
+Assumes that the cursor is in the first line of an item."
+  (goto-char
+   (min (save-excursion (org-end-of-item) (point))
+       (save-excursion
+         (goto-char (point-at-eol))
+         (if (re-search-forward (concat "^" (org-item-re t)) nil 'move)
+             (match-beginning 0)
+           (point-max))))))
+
 (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."
@@ -823,6 +867,10 @@ with something like \"1.\" or \"2)\"."
     (setq bobp (bobp))
     (looking-at "[ \t]*[0-9]+\\([.)]\\)")
     (setq fmt (concat "%d" (or (match-string 1) ".")))
+    (save-excursion
+      (goto-char (match-end 0))
+      (if (looking-at "[ \t]*\\[@start:\\([0-9]+\\)")
+         (setq n (1- (string-to-number (match-string 1))))))
     (beginning-of-line 0)
     ;; walk forward and replace these numbers
     (catch 'exit
@@ -961,12 +1009,24 @@ I.e. to the text after the last item."
 (defvar org-last-indent-end-marker (make-marker))
 
 (defun org-outdent-item (arg)
-  "Outdent a local list item."
+  "Outdent a local list item, but not its children."
   (interactive "p")
-  (org-indent-item (- arg)))
+  (org-indent-item-tree (- arg) 'no-subtree))
 
 (defun org-indent-item (arg)
-  "Indent a local list item."
+  "Indent a local list item, but not its children."
+  (interactive "p")
+  (org-indent-item-tree arg 'no-subtree))
+
+(defun org-outdent-item-tree (arg &optional no-subtree)
+  "Outdent a local list item including its children.
+If NO-SUBTREE is set, only outdent the item itself, not its children."
+  (interactive "p")
+  (org-indent-item-tree (- arg) no-subtree))
+
+(defun org-indent-item-tree (arg &optional no-subtree)
+  "Indent a local list item including its children.
+If NO-SUBTREE is set, only indent the item itself, not its children."
   (interactive "p")
   (and (org-region-active-p) (org-cursor-to-region-beginning))
   (unless (org-at-item-p)
@@ -975,12 +1035,15 @@ I.e. to the text after the last item."
     (setq firstp (org-first-list-item-p))
     (save-excursion
       (setq end (and (org-region-active-p) (region-end)))
-      (if (memq last-command '(org-shiftmetaright org-shiftmetaleft))
+      (if (and (memq last-command '(org-shiftmetaright org-shiftmetaleft))
+              (memq this-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)
+       (if no-subtree
+           (org-end-of-item-text-before-children)
+         (org-end-of-item))
        (setq end (move-marker org-last-indent-end-marker (or end (point)))))
       (goto-char beg)
       (setq ind-bul (org-item-indent-positions)
@@ -1108,7 +1171,7 @@ sublevels as a list of strings."
                                    (match-beginning 0)) end))))
             (item (buffer-substring
                    (point)
-                   (or (and (re-search-forward
+                   (or (and (org-re-search-forward-unprotected
                              org-list-beginning-re end t)
                             (goto-char (match-beginning 0)))
                        (goto-char end))))
@@ -1215,36 +1278,34 @@ this list."
     (save-excursion
       (org-list-goto-true-beginning)
       (beginning-of-line 0)
-      (unless (looking-at "#\\+ORGLST: *SEND +\\([a-zA-Z0-9_]+\\) +\\([^ \t\r\n]+\\)\\( +.*\\)?")
+      (unless (looking-at "[ \t]*#\\+ORGLST[: \t][ \t]*SEND[ \t]+\\([^ \t\r\n]+\\)[ \t]+\\([^ \t\r\n]+\\)\\([ \t]+.*\\)?")
        (if maybe
            (throw 'exit nil)
          (error "Don't know how to transform this list"))))
     (let* ((name (match-string 1))
           (transform (intern (match-string 2)))
           (item-beginning (org-list-item-beginning))
-          (txt (buffer-substring-no-properties
-                (car item-beginning)
-                (org-list-end (cdr item-beginning))))
-          (list (org-list-parse-list))
-          beg)
+          (list (save-excursion (org-list-goto-true-beginning)
+                                (org-list-parse-list)))
+          txt 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"))
+      (let ((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)
@@ -1326,7 +1387,7 @@ Valid parameters PARAMS are
 
 (defun org-list-to-latex (list &optional params)
   "Convert LIST into a LaTeX list.
-LIST is as returnd by `org-list-parse-list'.  PARAMS is a property list
+LIST is as returned by `org-list-parse-list'.  PARAMS is a property list
 with overruling parameters for `org-list-to-generic'."
   (org-list-to-generic
    list
@@ -1343,7 +1404,7 @@ with overruling parameters for `org-list-to-generic'."
 
 (defun org-list-to-html (list &optional params)
   "Convert LIST into a HTML list.
-LIST is as returnd by `org-list-parse-list'.  PARAMS is a property list
+LIST is as returned by `org-list-parse-list'.  PARAMS is a property list
 with overruling parameters for `org-list-to-generic'."
   (org-list-to-generic
    list
@@ -1360,7 +1421,7 @@ with overruling parameters for `org-list-to-generic'."
 
 (defun org-list-to-texinfo (list &optional params)
   "Convert LIST into a Texinfo list.
-LIST is as returnd by `org-list-parse-list'.  PARAMS is a property list
+LIST is as returned by `org-list-parse-list'.  PARAMS is a property list
 with overruling parameters for `org-list-to-generic'."
   (org-list-to-generic
    list