Browse Source

org-list: interactive navigation functions use accessors

* lisp/org-list.el (org-list-in-item-p): unify methods for this predicate.
(org-list-in-item-p-with-indent): removed function
(org-list-ending-between): removed function
(org-list-maybe-skip-block): removed function
(org-list-in-item-p-with-regexp): removed function
(org-list-top-point-with-regexp): removed function
(org-list-top-point-with-indent): removed function
(org-list-bottom-point-with-indent): removed function
(org-list-bottom-point-with-regexp): removed function
(org-list-get-item-same-level): removed function
(org-list-top-point): removed function
(org-list-bottom-point): removed function
(org-get-item-beginning): renamed to org-list-get-item-begin to be
consistent with naming policy of non-interactive functions.
(org-get-beginning-of-list): removed function
(org-beginning-of-item-list): use new accessors
(org-get-end-of-list): removed function
(org-end-of-list): use new accessors
(org-get-end-of-item): removed function
(org-end-of-item): use new accessors
(org-get-previous-item): removed function
(org-previous-item): use new accessors
(org-get-next-item): removed function
(org-next-item): use new accessors
(org-end-of-item-before-blank): renamed to
(org-list-get-item-end-before-blank): Use new accessors.
Nicolas Goaziou 15 years ago
parent
commit
e865ce445a
1 changed files with 133 additions and 389 deletions
  1. 133 389
      lisp/org-list.el

+ 133 - 389
lisp/org-list.el

@@ -419,40 +419,6 @@ Symbols `block' and `invalid' refer to `org-list-blocks'."
 	    ;; Return the closest context around
 	    ;; Return the closest context around
 	    (assq (apply 'max (mapcar 'car context-list)) context-list)))))))
 	    (assq (apply 'max (mapcar 'car context-list)) context-list)))))))
 
 
-(defun org-list-ending-between (min max &optional firstp)
-  "Find the position of a list ending between MIN and MAX, or nil.
-This function looks for `org-list-end-re' outside a block.
-
-If FIRSTP in non-nil, return the point at the beginning of the
-nearest valid terminator from MIN. Otherwise, return the point at
-the end of the nearest terminator from MAX."
-  (save-excursion
-    (let* ((start (if firstp min max))
-	   (end   (if firstp max min))
-	   (search-fun (if firstp
-			   #'org-search-forward-unenclosed
-			 #'org-search-backward-unenclosed))
-	   (list-end-p (progn
-			 (goto-char start)
-			 (funcall search-fun (org-list-end-re) end t))))
-      ;; Is there a valid list ending somewhere ?
-      (and list-end-p
-	   ;; we want to be on the first line of the list ender
-	   (match-beginning 0)))))
-
-(defun org-list-maybe-skip-block (search limit)
-  "Return non-nil value if point is in a block, skipping it on the way.
-It looks for the boundary of the block in SEARCH direction,
-stopping at LIMIT."
-  (save-match-data
-    (let ((case-fold-search t)
-	  (boundary (if (eq search 're-search-forward) 3 5)))
-    (when (save-excursion
-	    (and (funcall search "^[ \t]*#\\+\\(begin\\|end\\)_" limit t)
-		 (= (length (match-string 1)) boundary)))
-      ;; We're in a block: get out of it
-      (goto-char (match-beginning 0))))))
-
 (defun org-list-search-unenclosed-generic (search re bound noerr)
 (defun org-list-search-unenclosed-generic (search re bound noerr)
   "Search a string outside blocks and protected places.
   "Search a string outside blocks and protected places.
 Arguments SEARCH, RE, BOUND and NOERR are similar to those in
 Arguments SEARCH, RE, BOUND and NOERR are similar to those in
@@ -485,171 +451,6 @@ Arguments REGEXP, BOUND and NOERROR are similar to those used in
   (org-list-search-unenclosed-generic
   (org-list-search-unenclosed-generic
    #'re-search-forward regexp (or bound (point-max)) noerror))
    #'re-search-forward regexp (or bound (point-max)) noerror))
 
 
-(defun org-list-in-item-p-with-indent (limit)
-  "Is the cursor inside a plain list?
-Plain lists are considered ending when a non-blank line is less
-indented than the previous item within LIMIT."
-  (save-excursion
-    (beginning-of-line)
-    (cond
-     ;; do not start searching inside a block...
-     ((org-list-maybe-skip-block #'re-search-backward limit))
-     ;; ... or at a blank line
-     ((looking-at "^[ \t]*$")
-      (skip-chars-backward " \r\t\n")
-      (beginning-of-line)))
-    (beginning-of-line)
-    (or (org-at-item-p)
-	(let* ((case-fold-search t)
-	       (ind-ref (org-get-indentation))
-	       ;; Ensure there is at least an item above
-	       (up-item-p (save-excursion
-			    (org-search-backward-unenclosed
-			     org-item-beginning-re limit t))))
-	  (and up-item-p
-	       (catch 'exit
-		 (while t
-		   (cond
-		    ((org-at-item-p)
-		     (throw 'exit (< (org-get-indentation) ind-ref)))
-		    ((looking-at "^[ \t]*$")
-		     (skip-chars-backward " \r\t\n")
-		     (beginning-of-line))
-		    ((looking-at "^[ \t]*#\\+end_")
-		     (re-search-backward "^[ \t]*#\\+begin_"))
-		    (t
-		     (setq ind-ref (min (org-get-indentation) ind-ref))
-		     (forward-line -1))))))))))
-
-(defun org-list-in-item-p-with-regexp (limit)
-  "Is the cursor inside a plain list?
-Plain lists end when `org-list-end-regexp' is matched, or at a
-blank line if `org-empty-line-terminates-plain-lists' is true.
-
-Argument LIMIT specifies the upper-bound of the search."
-  (save-excursion
-    (let* ((actual-pos (goto-char (point-at-eol)))
-	   ;; Moved to eol so current line can be matched by
-	   ;; `org-item-re'.
-	   (last-item-start (save-excursion
-			      (org-search-backward-unenclosed
-			       org-item-beginning-re limit t)))
-	   (list-ender (org-list-ending-between
-			last-item-start actual-pos)))
-      ;; We are in a list when we are on an item line or when we can
-      ;; find an item before point and there is no valid list ender
-      ;; between it and the point.
-      (and last-item-start (not list-ender)))))
-
-(defun org-list-top-point-with-regexp (limit)
-  "Return point at the top level item in a list.
-Argument LIMIT specifies the upper-bound of the search.
-
-List ending is determined by regexp. See
-`org-list-ending-method'. for more information."
-  (save-excursion
-    (let ((pos (point-at-eol)))
-      ;; Is there some list above this one ? If so, go to its ending.
-      ;; Otherwise, go back to the heading above or bob.
-      (goto-char (or (org-list-ending-between limit pos) limit))
-      ;; From there, search down our list.
-      (org-search-forward-unenclosed org-item-beginning-re pos t)
-      (point-at-bol))))
-
-(defun org-list-bottom-point-with-regexp (limit)
-  "Return point just before list ending.
-Argument LIMIT specifies the lower-bound of the search.
-
-List ending is determined by regexp. See
-`org-list-ending-method'. for more information."
-  (save-excursion
-    (let ((pos (org-get-item-beginning)))
-      ;; The list ending is either first point matching
-      ;; `org-list-end-re', point at first white-line before next
-      ;; heading, or eob.
-      (or (org-list-ending-between (min pos limit) limit t) limit))))
-
-(defun org-list-top-point-with-indent (limit)
-  "Return point at the top level in a list.
-Argument LIMIT specifies the upper-bound of the search.
-
-List ending is determined by indentation of text. See
-`org-list-ending-method'. for more information."
-  (save-excursion
-    (let ((case-fold-search t))
-      (let ((item-ref (goto-char (org-get-item-beginning)))
-	    (ind-ref 10000))
-	(forward-line -1)
-	(catch 'exit
-	  (while t
-	    (let ((ind (+ (or (get-text-property (point) 'original-indentation) 0)
-			(org-get-indentation))))
-	      (cond
-	       ((looking-at "^[ \t]*:END:")
-		(throw 'exit item-ref))
-	       ((<= (point) limit)
-		(throw 'exit
-		       (if (and (org-at-item-p) (< ind ind-ref))
-			   (point-at-bol)
-			 item-ref)))
-	       ((looking-at "^[ \t]*$")
-		(skip-chars-backward " \r\t\n")
-		(beginning-of-line))
-	       ((looking-at "^[ \t]*#\\+end_")
-		(re-search-backward "^[ \t]*#\\+begin_"))
-	       ((not (org-at-item-p))
-		(setq ind-ref (min ind ind-ref))
-		(forward-line -1))
-	       ((>= ind ind-ref)
-		(throw 'exit item-ref))
-	       (t
-		(setq item-ref (point-at-bol) ind-ref 10000)
-		(forward-line -1))))))))))
-
-(defun org-list-bottom-point-with-indent (limit)
-  "Return point just before list ending or nil if not in a list.
-Argument LIMIT specifies the lower-bound of the search.
-
-List ending is determined by the indentation of text. See
-`org-list-ending-method' for more information."
-  (save-excursion
-    (let ((ind-ref (progn
-		     (goto-char (org-get-item-beginning))
-		     (org-get-indentation)))
-	  (case-fold-search t))
-      ;; do not start inside a block
-      (org-list-maybe-skip-block #'re-search-forward limit)
-      (beginning-of-line)
-      (catch 'exit
-	(while t
-	  (skip-chars-forward " \t")
-	  (let ((ind (+ (or (get-text-property (point) 'original-indentation) 0)
-			(org-get-indentation))))
-	    (cond
-	     ((or (>= (point) limit)
-		  (looking-at ":END:"))
-	      (throw 'exit (progn
-			     ;; Ensure bottom is just after a
-			     ;; non-blank line.
-			     (skip-chars-backward " \r\t\n")
-			     (min (point-max) (1+ (point-at-eol))))))
-	     ((= (point) (point-at-eol))
-	      (skip-chars-forward " \r\t\n")
-	      (beginning-of-line))
-	     ((org-at-item-p)
-	      (setq ind-ref ind)
-	      (forward-line 1))
-	     ((<= ind ind-ref)
-	      (throw 'exit (progn
-			     ;; Again, ensure bottom is just after a
-			     ;; non-blank line.
-			     (skip-chars-backward " \r\t\n")
-			     (min (point-max) (1+ (point-at-eol))))))
-	     ((looking-at "#\\+begin_")
-	      (re-search-forward "[ \t]*#\\+end_")
-	      (forward-line 1))
-	     (t (forward-line 1)))))))))
-
 (defun org-list-at-regexp-after-bullet-p (regexp)
 (defun org-list-at-regexp-after-bullet-p (regexp)
   "Is point at a list item with REGEXP after bullet?"
   "Is point at a list item with REGEXP after bullet?"
   (and (org-at-item-p)
   (and (org-at-item-p)
@@ -660,23 +461,6 @@ List ending is determined by the indentation of text. See
            (goto-char (match-end 0)))
            (goto-char (match-end 0)))
 	 (looking-at regexp))))
 	 (looking-at regexp))))
 
 
-(defun org-list-get-item-same-level (search-fun pos limit pre-move)
-  "Return point at the beginning of next item at the same level.
-Search items using function SEARCH-FUN, from POS to LIMIT. It
-uses PRE-MOVE before search. Return nil if no item was found."
-  (save-excursion
-    (goto-char pos)
-    (let* ((start (org-get-item-beginning))
-	   (ind (progn (goto-char start) (org-get-indentation))))
-      ;; We don't want to match the current line.
-      (funcall pre-move)
-      ;; Skip any sublist on the way
-      (while (and (funcall search-fun org-item-beginning-re limit t)
-		  (> (org-get-indentation) ind)))
-      (when (and (/= (point-at-bol) start) ; Have we moved ?
-		 (= (org-get-indentation) ind))
-	(point-at-bol)))))
-
 (defun org-list-separating-blank-lines-number (pos top bottom)
 (defun org-list-separating-blank-lines-number (pos top bottom)
   "Return number of blank lines that should separate items in list.
   "Return number of blank lines that should separate items in list.
 POS is the position of point to be considered.
 POS is the position of point to be considered.
@@ -744,7 +528,7 @@ function ends."
   (let* ((true-pos (point))
   (let* ((true-pos (point))
 	 (top (org-list-top-point))
 	 (top (org-list-top-point))
 	 (bottom (copy-marker (org-list-bottom-point)))
 	 (bottom (copy-marker (org-list-bottom-point)))
-	 (bullet (and (goto-char (org-get-item-beginning))
+	 (bullet (and (goto-char (org-list-get-item-begin))
 		      (org-list-bullet-string (org-get-bullet))))
 		      (org-list-bullet-string (org-get-bullet))))
          (ind (org-get-indentation))
          (ind (org-get-indentation))
 	 (before-p (progn
 	 (before-p (progn
@@ -761,7 +545,7 @@ function ends."
 	  (lambda (text)
 	  (lambda (text)
 	    ;; insert bullet above item in order to avoid bothering
 	    ;; insert bullet above item in order to avoid bothering
 	    ;; with possible blank lines ending last item.
 	    ;; with possible blank lines ending last item.
-	    (goto-char (org-get-item-beginning))
+	    (goto-char (org-list-get-item-begin))
             (org-indent-to-column ind)
             (org-indent-to-column ind)
 	    (insert (concat bullet (when checkbox "[ ] ") after-bullet))
 	    (insert (concat bullet (when checkbox "[ ] ") after-bullet))
 	    ;; Stay between after-bullet and before text.
 	    ;; Stay between after-bullet and before text.
@@ -773,7 +557,7 @@ function ends."
 	      (setq bottom (marker-position bottom))
 	      (setq bottom (marker-position bottom))
 	      (let ((col (current-column)))
 	      (let ((col (current-column)))
 		(org-list-exchange-items
 		(org-list-exchange-items
-		 (org-get-item-beginning) (org-get-next-item (point) bottom)
+		 (org-list-get-item-begin) (org-get-next-item (point) bottom)
 		 bottom)
 		 bottom)
 	      ;; recompute next-item: last sexp modified list
 	      ;; recompute next-item: last sexp modified list
 	      (goto-char (org-get-next-item (point) bottom))
 	      (goto-char (org-get-next-item (point) bottom))
@@ -910,32 +694,50 @@ Return t if successful."
 (defun org-in-item-p ()
 (defun org-in-item-p ()
   "Is the cursor inside a plain list?
   "Is the cursor inside a plain list?
 This checks `org-list-ending-method'."
 This checks `org-list-ending-method'."
-  (unless (let ((outline-regexp org-outline-regexp)) (org-at-heading-p))
-    (let* ((prev-head (save-excursion (outline-previous-heading)))
-	   (bound (if prev-head
-		      (or (save-excursion
-			    (let ((case-fold-search t))
-			      (re-search-backward "^[ \t]*:END:" prev-head t)))
-			  prev-head)
-		    (point-min))))
-      (cond
-       ((eq org-list-ending-method 'regexp)
-	(org-list-in-item-p-with-regexp bound))
-       ((eq org-list-ending-method 'indent)
-	(org-list-in-item-p-with-indent bound))
-       (t (and (org-list-in-item-p-with-regexp bound)
-	       (org-list-in-item-p-with-indent bound)))))))
-
-(defun org-list-first-item-p (top)
-  "Is this item the first item in a plain list?
-Assume point is at an item.
-
-TOP is the position of list's top-item."
   (save-excursion
   (save-excursion
     (beginning-of-line)
     (beginning-of-line)
-    (let ((ind (org-get-indentation)))
-      (or (not (org-search-backward-unenclosed org-item-beginning-re top t))
-	  (< (org-get-indentation) ind)))))
+    (unless (or (let ((outline-regexp org-outline-regexp)) (org-at-heading-p))
+		(and (not (eq org-list-ending-method 'indent))
+		     (looking-at (org-list-end-re))
+		     (progn (forward-line -1) (looking-at (org-list-end-re)))))
+      (or (and (org-at-item-p) (point-at-bol))
+	  (let* ((case-fold-search t)
+		 (context (org-list-context))
+		 (lim-up (car context))
+		 (inlinetask-re (and (featurep 'org-inlinetask)
+				     (org-inlinetask-outline-regexp)))
+		 (ind-ref (if (looking-at "^[ \t]*$")
+			      10000
+			    (org-get-indentation))))
+	    (catch 'exit
+	      (while t
+		(let ((ind (org-get-indentation)))
+		  (cond
+		   ((<= (point) lim-up)
+		    (throw 'exit (and (org-at-item-p) (< ind ind-ref))))
+		   ((and (not (eq org-list-ending-method 'indent))
+			 (looking-at (org-list-end-re)))
+		    (throw 'exit nil))
+		   ;; Skip blocks, drawers, inline-tasks, blank lines
+		   ((looking-at "^[ \t]*#\\+end_")
+		    (re-search-backward "^[ \t]*#\\+begin_" nil t))
+		   ((looking-at "^[ \t]*:END:")
+		    (re-search-backward org-drawer-regexp nil t)
+		    (beginning-of-line))
+		   ((and inlinetask-re (looking-at inlinetask-re))
+		    (org-inlinetask-goto-beginning)
+		    (forward-line -1))
+		   ((looking-at "^[ \t]*$")
+		    (forward-line -1))
+		   ((< ind ind-ref)
+		    (if (org-at-item-p)
+			(throw 'exit (point))
+		      (setq ind-ref ind)
+		      (forward-line -1)))
+		   (t (if (and (eq org-list-ending-method 'regexp)
+			       (org-at-item-p))
+			  (throw 'exit (point))
+			(forward-line -1))))))))))))
 
 
 (defun org-at-item-p ()
 (defun org-at-item-p ()
   "Is point in a line starting a hand-formatted item?"
   "Is point in a line starting a hand-formatted item?"
@@ -963,178 +765,86 @@ TOP is the position of list's top-item."
 
 
 ;;; Navigate
 ;;; Navigate
 
 
-;; Every interactive navigation function is derived from a
-;; non-interactive one, which doesn't move point, assumes point is
-;; already in a list and doesn't compute list boundaries.
-
-;; If you plan to use more than one org-list function is some code,
-;; you should therefore first check if point is in a list with
-;; `org-in-item-p' or `org-at-item-p', then compute list boundaries
-;; with `org-list-top-point' and `org-list-bottom-point', and make use
-;; of non-interactive forms.
-
-(defun org-list-top-point ()
-  "Return point at the top level in a list.
-Assume point is in a list."
-  (let* ((prev-head (save-excursion (outline-previous-heading)))
-	 (bound (if prev-head
-		    (or (save-excursion
-			  (let ((case-fold-search t))
-			    (re-search-backward "^[ \t]*:END:" prev-head t)))
-			prev-head)
-		  (point-min))))
-    (cond
-     ((eq org-list-ending-method 'regexp)
-      (org-list-top-point-with-regexp bound))
-     ((eq org-list-ending-method 'indent)
-      (org-list-top-point-with-indent bound))
-     (t (let ((top-re (org-list-top-point-with-regexp bound)))
-	  (org-list-top-point-with-indent (or top-re bound)))))))
-
-(defun org-list-bottom-point ()
-  "Return point just before list ending.
-Assume point is in a list."
-  (let* ((next-head (save-excursion
-		      (and (let ((outline-regexp org-outline-regexp))
-			     ;; Use default regexp because folding
-			     ;; changes OUTLINE-REGEXP.
-			     (outline-next-heading)))))
-	 (limit (or (save-excursion
-		      (and (re-search-forward "^[ \t]*:END:" next-head t)
-			   (point-at-bol)))
-		    next-head
-		    (point-max))))
-    (cond
-     ((eq org-list-ending-method 'regexp)
-      (org-list-bottom-point-with-regexp limit))
-     ((eq org-list-ending-method 'indent)
-      (org-list-bottom-point-with-indent limit))
-     (t (let ((bottom-re (org-list-bottom-point-with-regexp limit)))
-	  (org-list-bottom-point-with-indent (or bottom-re limit)))))))
-
-(defun org-get-item-beginning ()
-  "Return position of current item beginning."
-  (save-excursion
-    ;; possibly match current line
-    (end-of-line)
-    (org-search-backward-unenclosed org-item-beginning-re nil t)
-    (point-at-bol)))
+(defalias 'org-list-get-item-begin 'org-in-item-p)
 
 
 (defun org-beginning-of-item ()
 (defun org-beginning-of-item ()
   "Go to the beginning of the current hand-formatted item.
   "Go to the beginning of the current hand-formatted item.
 If the cursor is not in an item, throw an error."
 If the cursor is not in an item, throw an error."
   (interactive)
   (interactive)
-  (if (org-in-item-p)
-      (goto-char (org-get-item-beginning))
-    (error "Not in an item")))
-
-(defun org-get-beginning-of-list (top)
-  "Return position of the first item of the current list or sublist.
-TOP is the position at list beginning."
-  (save-excursion
-    (let (prev-p)
-      (while (setq prev-p (org-get-previous-item (point) top))
-	(goto-char prev-p))
-      (point-at-bol))))
+  (let ((begin (org-in-item-p)))
+    (if begin (goto-char begin) (error "Not in an item"))))
 
 
 (defun org-beginning-of-item-list ()
 (defun org-beginning-of-item-list ()
   "Go to the beginning item of the current list or sublist.
   "Go to the beginning item of the current list or sublist.
 Return an error if not in a list."
 Return an error if not in a list."
   (interactive)
   (interactive)
-  (if (org-in-item-p)
-      (goto-char (org-get-beginning-of-list (org-list-top-point)))
-    (error "Not in an item")))
-
-(defun org-get-end-of-list (bottom)
-  "Return position at the end of the current list or sublist.
-BOTTOM is the position at list ending."
-  (save-excursion
-    (goto-char (org-get-item-beginning))
-    (let ((ind (org-get-indentation)))
-      (while (and (/= (point) bottom)
-		  (>= (org-get-indentation) ind))
-	(org-search-forward-unenclosed org-item-beginning-re bottom 'move))
-      (if (= (point) bottom) bottom (point-at-bol)))))
+  (let ((begin (org-in-item-p)))
+    (if (not begin)
+	(error "Not in an item")
+      (goto-char begin)
+      (let ((struct (org-list-struct)))
+	(goto-char (org-list-get-list-begin begin (org-list-struct)))))))
 
 
 (defun org-end-of-item-list ()
 (defun org-end-of-item-list ()
   "Go to the end of the current list or sublist.
   "Go to the end of the current list or sublist.
 If the cursor in not in an item, throw an error."
 If the cursor in not in an item, throw an error."
   (interactive)
   (interactive)
-  (if (org-in-item-p)
-      (goto-char (org-get-end-of-list (org-list-bottom-point)))
-    (error "Not in an item")))
-
-(defun org-get-end-of-item (bottom)
-  "Return position at the end of the current item.
-BOTTOM is the position at list ending."
-  (or (org-get-next-item (point) bottom)
-      (org-get-end-of-list bottom)))
+  (let ((begin (org-in-item-p)))
+    (if (not begin)
+	(error "Not in an item")
+      (goto-char begin)
+      (let ((struct (org-list-struct)))
+	(goto-char (org-list-get-list-end begin (org-list-struct)))))))
 
 
 (defun org-end-of-item ()
 (defun org-end-of-item ()
   "Go to the end of the current hand-formatted item.
   "Go to the end of the current hand-formatted item.
 If the cursor is not in an item, throw an error."
 If the cursor is not in an item, throw an error."
   (interactive)
   (interactive)
-  (if (org-in-item-p)
-      (goto-char (org-get-end-of-item (org-list-bottom-point)))
-    (error "Not in an item")))
-
-(defun org-end-of-item-or-at-child (bottom)
-  "Move to the end of the item, stops before the first child if any.
-BOTTOM is the position at list ending."
-  (end-of-line)
-  (goto-char
-   (if (org-search-forward-unenclosed org-item-beginning-re bottom t)
-       (point-at-bol)
-     (org-get-end-of-item bottom))))
-
-(defun org-end-of-item-before-blank (bottom)
-  "Return point at end of item, before any blank line.
-Point returned is at eol.
-
-BOTTOM is the position at list ending."
-  (save-excursion
-    (goto-char (org-get-end-of-item bottom))
-    (skip-chars-backward " \r\t\n")
-    (point-at-eol)))
-
-(defun org-get-previous-item (pos limit)
-  "Return point of the previous item at the same level as POS.
-Stop searching at LIMIT. Return nil if no item is found."
-  (org-list-get-item-same-level
-   #'org-search-backward-unenclosed pos limit #'beginning-of-line))
+  (let ((begin (org-in-item-p)))
+    (if (not begin)
+	(error "Not in an item")
+      (goto-char begin)
+      (let ((struct (org-list-struct)))
+	(goto-char (org-list-get-item-end begin struct))))))
 
 
 (defun org-previous-item ()
 (defun org-previous-item ()
   "Move to the beginning of the previous item.
   "Move to the beginning of the previous item.
 Item is at the same level in the current plain list. Error if not
 Item is at the same level in the current plain list. Error if not
 in a plain list, or if this is the first item in the list."
 in a plain list, or if this is the first item in the list."
   (interactive)
   (interactive)
-  (if (not (org-in-item-p))
-      (error "Not in an item")
-    (let ((prev-p (org-get-previous-item (point) (org-list-top-point))))
-      (if prev-p (goto-char prev-p) (error "On first item")))))
-
-(defun org-get-next-item (pos limit)
-  "Return point of the next item at the same level as POS.
-Stop searching at LIMIT. Return nil if no item is found."
-  (org-list-get-item-same-level
-   #'org-search-forward-unenclosed pos limit #'end-of-line))
+  (let ((begin (org-in-item-p)))
+    (if (not begin)
+	(error "Not in an item")
+      (goto-char begin)
+      (let* ((struct (org-list-struct))
+	     (prevs (org-list-struct-prev-alist struct))
+	     (prevp (org-list-get-prev-item begin struct prevs)))
+	(if prevp (goto-char prevp) (error "On first item"))))))
 
 
 (defun org-next-item ()
 (defun org-next-item ()
   "Move to the beginning of the next item.
   "Move to the beginning of the next item.
 Item is at the same level in the current plain list. Error if not
 Item is at the same level in the current plain list. Error if not
 in a plain list, or if this is the last item in the list."
 in a plain list, or if this is the last item in the list."
   (interactive)
   (interactive)
-  (if (not (org-in-item-p))
-      (error "Not in an item")
-    (let ((next-p (org-get-next-item (point) (org-list-bottom-point))))
-      (if next-p (goto-char next-p) (error "On last item")))))
+  (let ((begin (org-in-item-p)))
+    (if (not begin)
+	(error "Not in an item")
+      (goto-char begin)
+      (let* ((struct (org-list-struct))
+	     (prevs (org-list-struct-prev-alist struct))
+	     (prevp (org-list-get-next-item begin struct prevs)))
+	(if prevp (goto-char prevp) (error "On last item"))))))
 
 
 ;;; Manipulate
 ;;; Manipulate
 
 
 (defun org-list-exchange-items (beg-A beg-B struct)
 (defun org-list-exchange-items (beg-A beg-B struct)
-  "Swap item starting at BEG-A with item starting at BEG-B.
-Blank lines at the end of items are left in place. Assume BEG-A
-is lesser than BEG-B."
+  "Swap item starting at BEG-A with item starting at BEG-B in STRUCT.
+Blank lines at the end of items are left in place.
+
+Assume BEG-A is lesser than BEG-B and that BEG-A and BEG-B
+belong to the same sub-list.
+
+This function modifies STRUCT."
   (save-excursion
   (save-excursion
     (let* ((end-of-item-no-blank
     (let* ((end-of-item-no-blank
 	    (lambda (pos)
 	    (lambda (pos)
@@ -1146,7 +856,21 @@ is lesser than BEG-B."
 	   (between-A-no-blank-and-B (buffer-substring end-A-no-blank beg-B)))
 	   (between-A-no-blank-and-B (buffer-substring end-A-no-blank beg-B)))
       (goto-char beg-A)
       (goto-char beg-A)
       (delete-region beg-A end-B-no-blank)
       (delete-region beg-A end-B-no-blank)
-      (insert (concat body-B between-A-no-blank-and-B body-A)))))
+      (insert (concat body-B between-A-no-blank-and-B body-A))
+      ;; Now modify struct. No need to re-read the list, the
+      ;; transformation is just a shift of positions
+      (let* ((sub-A (cons beg-A (org-list-get-subtree beg-A struct)))
+	     (sub-B (cons beg-B (org-list-get-subtree beg-B struct)))
+	     (end-A (org-list-get-item-end beg-A struct))
+	     (end-B (org-list-get-item-end beg-B struct))
+	     (inter-A-B (- beg-B end-A))
+	     (size-A (- end-A beg-A))
+	     (size-B (- end-B beg-B)))
+	(mapc (lambda (e) (org-list-set-pos e struct (+ e size-B inter-A-B)))
+	      sub-A)
+	(mapc (lambda (e) (org-list-set-pos e struct (- e size-A inter-A-B)))
+	      sub-B)
+	(sort struct (lambda (e1 e2) (< (car e1) (car e2))))))))
 
 
 (defun org-move-item-down ()
 (defun org-move-item-down ()
   "Move the plain list item at point down, i.e. swap with following item.
   "Move the plain list item at point down, i.e. swap with following item.
@@ -1164,12 +888,17 @@ so this really moves item trees."
 	(progn
 	(progn
 	  (goto-char pos)
 	  (goto-char pos)
 	  (error "Cannot move this item further down"))
 	  (error "Cannot move this item further down"))
-      (let ((next-item-size (- (org-list-get-item-end next-item struct)
-			       next-item)))
-	(org-list-exchange-items actual-item next-item struct)
-	(org-list-repair)
-	(goto-char (+ (point) next-item-size))
-	(org-move-to-column col)))))
+      (org-list-exchange-items actual-item next-item struct)
+      ;; Use a short variation of `org-list-struct-fix-struct' as
+      ;; there's no need to go through all the steps.
+      (let ((old-struct (mapcar (lambda (e) (copy-alist e)) struct))
+	    (prevs (org-list-struct-prev-alist struct))
+	    (parents (org-list-struct-parent-alist struct)))
+        (org-list-struct-fix-bul struct prevs)
+        (org-list-struct-fix-ind struct parents)
+        (org-list-struct-apply-struct struct old-struct)
+	(goto-char (org-list-get-next-item (point-at-bol) struct prevs)))
+      (org-move-to-column col))))
 
 
 (defun org-move-item-up ()
 (defun org-move-item-up ()
   "Move the plain list item at point up, i.e. swap with previous item.
   "Move the plain list item at point up, i.e. swap with previous item.
@@ -1188,7 +917,14 @@ so this really moves item trees."
 	  (goto-char pos)
 	  (goto-char pos)
 	  (error "Cannot move this item further up"))
 	  (error "Cannot move this item further up"))
       (org-list-exchange-items prev-item actual-item struct)
       (org-list-exchange-items prev-item actual-item struct)
-      (org-list-repair)
+      ;; Use a short variation of `org-list-struct-fix-struct' as
+      ;; there's no need to go through all the steps.
+      (let ((old-struct (mapcar (lambda (e) (copy-alist e)) struct))
+	    (prevs (org-list-struct-prev-alist struct))
+	    (parents (org-list-struct-parent-alist struct)))
+        (org-list-struct-fix-bul struct prevs)
+        (org-list-struct-fix-ind struct parents)
+        (org-list-struct-apply-struct struct old-struct))
       (org-move-to-column col))))
       (org-move-to-column col))))
 
 
 (defun org-insert-item (&optional checkbox)
 (defun org-insert-item (&optional checkbox)
@@ -1205,13 +941,13 @@ item is invisible."
 		(goto-char (org-get-item-beginning))
 		(goto-char (org-get-item-beginning))
 		(outline-invisible-p)))
 		(outline-invisible-p)))
     (if (save-excursion
     (if (save-excursion
-	  (goto-char (org-get-item-beginning))
+	  (goto-char (org-list-get-item-begin))
 	  (org-at-item-timer-p))
 	  (org-at-item-timer-p))
 	;; Timer list: delegate to `org-timer-item'.
 	;; Timer list: delegate to `org-timer-item'.
 	(progn (org-timer-item) t)
 	(progn (org-timer-item) t)
       ;; if we're in a description list, ask for the new term.
       ;; if we're in a description list, ask for the new term.
       (let ((desc-text (when (save-excursion
       (let ((desc-text (when (save-excursion
-			       (and (goto-char (org-get-item-beginning))
+			       (and (goto-char (org-list-get-item-begin))
 				    (org-at-item-description-p)))
 				    (org-at-item-description-p)))
 			 (concat (read-string "Term: ") " :: "))))
 			 (concat (read-string "Term: ") " :: "))))
         ;; Don't insert a checkbox if checkbox rule is applied and it
         ;; Don't insert a checkbox if checkbox rule is applied and it
@@ -1612,6 +1348,14 @@ previous items. See `org-list-struct-prev-alist'."
   "Return end position of ITEM in STRUCT."
   "Return end position of ITEM in STRUCT."
   (org-list-get-nth 5 item struct))
   (org-list-get-nth 5 item struct))
 
 
+(defun org-list-get-item-end-before-blank (item struct)
+  "Return point at end of item, before any blank line.
+Point returned is at end of line."
+  (save-excursion
+    (goto-char (org-list-get-item-end item struct))
+    (skip-chars-backward " \r\t\n")
+    (point-at-eol)))
+
 (defun org-list-struct-fix-bul (struct prevs)
 (defun org-list-struct-fix-bul (struct prevs)
   "Verify and correct bullets for every association in STRUCT.
   "Verify and correct bullets for every association in STRUCT.
 \nThis function modifies STRUCT."
 \nThis function modifies STRUCT."