Indentation is faster and now correct. Indenting region is back.

This commit is contained in:
Nicolas Goaziou 2010-07-31 00:45:34 +02:00
parent 030fc40b1d
commit 9eab167626
1 changed files with 387 additions and 217 deletions

View File

@ -140,7 +140,7 @@ the safe choice."
(defcustom org-list-two-spaces-after-bullet-regexp nil
"A regular expression matching bullets that should have 2 spaces after them.
When nil, no bullet will have two spaces after them.
When a string, it will be used as a regular expression. When the
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 the list."
@ -157,7 +157,7 @@ Otherwise, look for `org-list-end-regexp'."
(defcustom org-list-end-regexp "^[ \t]*\n[ \t]*\n"
"Regexp matching the end of all plain list levels.
It must start with \"^\" and end with \"\\n\". It defaults to 2
It must start with \"^\" and end with \"\\n\". It defaults to 2
blank lines. `org-empty-line-terminates-plain-lists' has
precedence over it."
:group 'org-plain-lists
@ -186,8 +186,7 @@ checkbox when non-nil, checkbox statistics is updated each time
It also prevents from inserting a checkbox in a
description item.
indent when non-nil indenting or outdenting list top-item with
its subtree will move the whole list, all moves that
would break list will be forbidden, and outdenting a
its subtree will move the whole list and outdenting a
list whose bullet is * to column 0 will change that
bullet to -.
insert when non-nil, trying to insert an item inside a block
@ -642,6 +641,17 @@ Return point."
(goto-char (funcall move-up (point) limit))
(goto-char (point-at-bol))))
(defun org-list-last-item ()
"Go to the last item of the current list.
Return point."
(let* ((limit (org-list-bottom-point))
(get-last-item
(lambda (pos)
(let ((next-p (org-get-next-item pos limit)))
(if next-p (funcall get-last-item next-p) pos)))))
(org-beginning-of-item)
(goto-char (funcall get-last-item (point)))))
(defun org-end-of-item-list ()
"Go to the end of the current list or sublist.
Return point."
@ -746,6 +756,267 @@ invisible."
(not (cdr (assq 'checkbox org-list-automatic-rules)))))
desc-text)))))
;;; Structures
;; The idea behind structures is to avoid moving back and forth in the
;; buffer on costly operations like indenting or fixing bullets.
;; It achieves this by taking a snapshot of an interesting part of the
;; list, in the shape of an alist, with `org-list-struct'.
;; It then proceeds to changes directly on the alist. When those are
;; done, `org-list-struct-apply-struct' applies the changes in the
;; buffer.
(defun org-list-struct-assoc-at-point ()
"Return the structure association at point.
It is a cons-cell whose key is point and values are indentation,
bullet string and bullet counter, if any."
(save-excursion
(beginning-of-line)
(list (point-at-bol)
(org-get-indentation)
(progn
(looking-at "^[ \t]*\\([-+*0-9.)]+[ \t]+\\)")
(match-string 1))
(progn
(goto-char (match-end 0))
(and (looking-at "\\[@start:\\([0-9]+\\)\\]")
(match-string 1))))))
(defun org-list-struct (begin end &optional outdent)
"Return the structure containing the list between BEGIN and END.
A structure is an alist where key is point of item and values
are, in that order, indentation, bullet string and value of
counter if any. The structure contains every list and sublist
that has items between BEGIN and END and their common parent, if
any.
If OUTDENT is non-nil, it will also grab all of the parent list
and the grand-parent. Setting OUTDENT to t is mandatory when next
change is an outdent."
(save-excursion
(let* ((top (org-list-top-point))
(bottom (org-list-bottom-point))
struct
(extend
(lambda (struct)
(let* ((ind-min (apply 'min (mapcar 'cadr struct)))
(begin (caar struct))
(end (caar (last struct)))
pre-list post-list)
(goto-char begin)
;; Find beginning of most outdented list (min list)
(while (and (org-search-backward-unenclosed org-item-beginning-re top t)
(>= (org-get-indentation) ind-min))
(setq pre-list (cons (org-list-struct-assoc-at-point) pre-list)))
;; Now get the parent, if any. If not, add a virtual
;; ancestor at position 0.
(if (< (org-get-indentation) ind-min)
(setq pre-list (cons (org-list-struct-assoc-at-point) pre-list))
(setq pre-list (cons (list 0 (org-get-indentation) "" nil) pre-list)))
;; Find end of min list
(goto-char end)
(end-of-line)
(while (and (org-search-forward-unenclosed org-item-beginning-re bottom t)
(>= (org-get-indentation) ind-min))
(setq post-list (cons (org-list-struct-assoc-at-point) post-list)))
(append pre-list struct (reverse post-list))))))
;; Here we start: first get the core zone...
(goto-char end)
(while (org-search-backward-unenclosed org-item-beginning-re begin t)
(setq struct (cons (org-list-struct-assoc-at-point) struct)))
;; ... then, extend it to make it a structure...
(let ((extended (funcall extend struct)))
;; ... twice when OUTDENT is non-nil and struct still can be
;; extended
(if (and outdent (> (caar extended) 0))
(funcall extend extended)
extended)))))
(defun org-list-struct-origins (struct)
"Return an alist where key is item's position and value parent's.
Common ancestor of structure is, as a convention, at position 0."
(let* ((struct-rev (reverse struct))
(prev-item (lambda (item) (car (nth 1 (member (assq item struct) struct-rev)))))
(get-origins
(lambda (item)
(let* ((item-pos (car item))
(ind (nth 1 item))
(prev-ind (caar acc)))
(cond
;; List closing.
((> prev-ind ind)
(setq acc (member (assq ind acc) acc))
(cons item-pos (cdar acc)))
;; New list
((< prev-ind ind)
(let ((origin (funcall prev-item item-pos)))
(setq acc (cons (cons ind origin) acc))
(cons item-pos origin)))
;; Current list going on
(t (cons item-pos (cdar acc)))))))
(acc (list (cons (nth 1 (car struct)) 0))))
(cons '(0 . 0) (mapcar get-origins (cdr struct)))))
(defun org-list-struct-get-parent (item struct origins)
"Return parent association of ITEM in STRUCT or nil."
(let* ((parent-pos (cdr (assq (car item) origins))))
(when (> parent-pos 0) (assq parent-pos struct))))
(defun org-list-struct-get-child (item struct)
"Return child association of ITEM in STRUCT or nil."
(let ((ind (nth 1 item))
(next-item (cadr (member item struct))))
(when (and next-item (> (nth 1 next-item) ind)) next-item)))
(defun org-list-struct-fix-bul (struct origins)
"Verify and correct bullets for every association in STRUCT.
This function modifies STRUCT."
(let* ((init-bul (lambda (item)
(let ((counter (nth 3 item))
(bullet (org-list-bullet-string (nth 2 item))))
(cond
((and (string-match "[0-9]+" bullet) counter)
(replace-match counter nil nil bullet))
((string-match "[0-9]+" bullet)
(replace-match "1" nil nil bullet))
(t bullet)))))
(set-bul (lambda (item bullet)
(setcdr item (list (nth 1 item) bullet (nth 3 item)))))
(get-bul (lambda (item bullet)
(let* ((counter (nth 3 item)))
(if (and counter (string-match "[0-9]+" bullet))
(replace-match counter nil nil bullet)
bullet))))
(fix-bul
(lambda (item) struct
(let* ((parent (cdr (assq (car item) origins)))
(orig-ref (assq parent acc)))
(if orig-ref
;; Continuing previous list
(let* ((prev-bul (cdr orig-ref))
(new-bul (funcall get-bul item prev-bul)))
(setcdr orig-ref (org-list-inc-bullet-maybe new-bul))
(funcall set-bul item new-bul))
;; A new list is starting
(let ((new-bul (funcall init-bul item)))
(funcall set-bul item new-bul)
(setq acc (cons (cons parent (org-list-inc-bullet-maybe new-bul)) acc)))))))
acc)
(mapc fix-bul (cdr struct))))
(defun org-list-struct-fix-ind (struct origins)
"Verify and correct indentation for every association in STRUCT.
This function modifies STRUCT."
(let* ((headless (cdr struct))
(ancestor (car struct))
(top-ind (+ (nth 1 ancestor) (length (nth 2 ancestor))))
(new-ind
(lambda (item)
(let* ((parent (org-list-struct-get-parent item headless origins)))
(if parent
;; Indent like parent + length of parent's bullet
(setcdr item (cons (+ (length (nth 2 parent)) (nth 1 parent)) (cddr item)))
;; If no parent, indent like top-point
(setcdr item (cons top-ind (cddr item))))))))
(mapc new-ind headless)))
(defun org-list-struct-fix-struct (struct origins)
"Return STRUCT with correct bullets and indentation.
Only elements of STRUCT that have changed are returned."
(let ((before (copy-alist struct))
(set-diff (lambda (setA setB result)
(cond
((null setA) result)
((equal (car setA) (car setB))
(funcall set-diff (cdr setA) (cdr setB) result))
(t (funcall set-diff (cdr setA) (cdr setB) (cons (car setA) result)))))))
(org-list-struct-fix-bul struct origins)
(org-list-struct-fix-ind struct origins)
(nreverse (funcall set-diff struct before nil))))
(defun org-list-struct-outdent (start end origins)
"Outdent items in ORIGINS between BEGIN and END.
BEGIN is included and END excluded."
(let ((out (lambda (cell)
(let* ((item (car cell))
(parent (cdr cell)))
(cond
;; Item not yet in zone: keep association
((< item start) cell)
;; Item out of zone: follow associations in acc
((>= item end)
(let ((convert (assq parent acc)))
(if convert (cons item (cdr convert)) cell)))
;; Item has no parent: error
((<= parent 0)
(error "Cannot outdent top-level items"))
;; Parent is outdented: keep association
((>= parent start)
(setq acc (cons (cons parent item) acc)) cell)
(t
;; Parent isn't outdented: reparent to grand-parent
(let ((grand-parent (cdr (assq parent origins))))
(setq acc (cons (cons parent item) acc))
(cons item grand-parent)))))))
acc)
(mapcar out origins)))
(defun org-list-struct-indent (start end origins)
"Indent items in ORIGINS between BEGIN and END.
BEGIN is included and END excluded."
(let* ((orig-rev (reverse origins))
(get-prev-item (lambda (cell parent)
(car (rassq parent (cdr (memq cell orig-rev))))))
(set-assoc (lambda (cell)
(setq acc (cons cell acc)) cell))
(ind
(lambda (cell)
(let* ((item (car cell))
(parent (cdr cell)))
(cond
;; Item not yet in zone: keep association
((< item start) cell)
((>= item end)
;; Item out of zone: follow associations in acc
(let ((convert (assq parent acc)))
(if convert (cons item (cdr convert)) cell)))
(t
;; Item is in zone...
(let ((prev (funcall get-prev-item cell parent)))
(cond
;; First item indented but not parent: error
((and (or (not prev) (= prev 0)) (< parent start))
(error "Cannot indent the first item of a list"))
;; First item and parent indented: keep same parent
((or (not prev) (= prev 0))
(funcall set-assoc cell))
;; Previous item not indented: reparent to it
((< prev start)
(funcall set-assoc (cons item prev)))
;; Previous item indented: reparent like it
(t
(funcall set-assoc (cons item (cdr (assq prev acc))))))))))))
acc)
(mapcar ind origins)))
(defun org-list-struct-apply-struct (struct)
"Apply modifications to list so it mirrors STRUCT.
Initial position is restored after the changes."
(let* ((pos (copy-marker (point)))
(modify
(lambda (item)
(goto-char (car item))
(org-list-indent-item (nth 1 item))
(org-list-replace-bullet (org-list-bullet-string (nth 2 item)))))
;; Remove ancestor if it is left.
(struct-to-apply (if (= 0 (caar struct)) (cdr struct) struct)))
;; Apply changes from bottom to top
(mapc modify (nreverse struct-to-apply))
(goto-char pos)))
;;; Indentation
(defun org-get-string-indentation (s)
@ -760,11 +1031,12 @@ invisible."
i))
(defun org-shift-item-indentation (delta)
"Shift the indentation in current item by DELTA."
"Shift the indentation in current item by DELTA.
Sub-items are not moved."
(save-excursion
(let ((beg (point-at-bol))
(end (org-end-of-item)))
(beginning-of-line 0)
(end (org-end-of-item-or-at-child)))
(beginning-of-line (unless (eolp) 0))
(while (> (point) beg)
(when (looking-at "[ \t]*\\S-")
;; this is not an empty line
@ -773,18 +1045,27 @@ invisible."
(indent-line-to (+ i delta)))))
(beginning-of-line 0)))))
(defvar org-last-indent-begin-marker (make-marker))
(defvar org-last-indent-end-marker (make-marker))
(defun org-list-indent-item (ind)
"Change indentation of item at point to IND.
It does not move sub-lists."
(save-excursion
(beginning-of-line)
(let ((old-ind (org-get-indentation)))
(unless (= ind old-ind)
(org-shift-item-indentation (- ind old-ind))
(skip-chars-forward " \t")
(delete-region (point-at-bol) (point))
(org-indent-to-column ind)))))
(defun org-outdent-item (arg)
"Outdent a local list item, but not its children."
(interactive "p")
(org-indent-item-tree (- arg) 'no-subtree))
(org-indent-item-tree (- arg) t))
(defun org-indent-item (arg)
"Indent a local list item, but not its children."
(interactive "p")
(org-indent-item-tree arg 'no-subtree))
(org-indent-item-tree arg t))
(defun org-outdent-item-tree (arg &optional no-subtree)
"Outdent a local list item including its children.
@ -792,169 +1073,69 @@ If NO-SUBTREE is set, only outdent the item itself, not its children."
(interactive "p")
(org-indent-item-tree (- arg) no-subtree))
(defvar org-last-indent-begin-marker (make-marker))
(defvar org-last-indent-end-marker (make-marker))
(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. Return t if sucessful."
children. Return t if successful."
(interactive "p")
(unless (org-at-item-p)
(error "Not on an item"))
(let ((line (org-current-line))
(col (current-column))
(pos (point))
(origin-ind (save-excursion
(goto-char (org-list-top-point))
(org-get-indentation)))
beg end ind ind1 ind-pos bullet delta ind-down ind-up)
;; If moving a subtree, don't drag additional items on subsequent
;; moves.
(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)))
;; Determine end point of indentation
(if no-subtree (org-end-of-item-or-at-child) (org-end-of-item))
(setq end (move-marker org-last-indent-end-marker (or end (point)))))
;; Get some information
(goto-char beg)
(setq ind-pos (org-item-indent-positions)
bullet (cdr (car ind-pos))
bul-up (cdr (nth 1 ind-pos))
bul-down (cdr (nth 2 ind-pos))
ind (caar ind-pos)
ind-down (car (nth 2 ind-pos))
ind-up (car (nth 1 ind-pos))
delta (if (> arg 0)
(if ind-down (- ind-down ind) 2)
(if ind-up (- ind-up ind) -2)))
;; Check for error cases.
;; Determine begin and end points of zone to indent. If moving by
;; subtrees, ensure we don't drag additional items on subsequent
;; moves.
(unless (and (memq last-command '(org-shiftmetaright org-shiftmetaleft))
(memq this-command '(org-shiftmetaright org-shiftmetaleft)))
(if (org-region-active-p)
(progn
(set-marker org-last-indent-begin-marker (region-beginning))
(set-marker org-last-indent-end-marker (region-end)))
(set-marker org-last-indent-begin-marker (save-excursion (org-beginning-of-item)))
(set-marker org-last-indent-end-marker
(save-excursion
(if no-subtree (org-end-of-item-or-at-child) (org-end-of-item))))))
;; Get everything ready
(let* ((beg (marker-position org-last-indent-begin-marker))
(end (marker-position org-last-indent-end-marker))
(struct (org-list-struct beg end (< arg 0)))
(origins (org-list-struct-origins struct))
(beg-item (assq beg struct))
(end-item (save-excursion
(goto-char end)
(skip-chars-backward " \r\t\n")
(org-beginning-of-item)
(org-list-struct-assoc-at-point)))
(top (org-list-top-point)))
(cond
((< (+ delta ind) 0)
(goto-char pos)
(error "Cannot outdent beyond margin"))
;; Apply indent rules if activated.
((cdr (assq 'indent org-list-automatic-rules))
(cond
;; 1. If at top-point move the whole list. Moreover, if
;; *-list is going to column 0, change bullet to "-".
((and (= (point-at-bol) (org-list-top-point))
(not no-subtree))
(when (and (= (+ delta ind) 0) (equal bullet "*"))
(org-fix-bullet-type (setq bullet "-")))
(setq end (set-marker org-last-indent-end-marker (org-list-bottom-point))))
;; 2. Do not indent before top-item.
((< (+ delta ind) origin-ind)
(goto-char pos)
(error "Cannot outdent beyond top level item"))
;; 3. Do not indent the first item of a list.
((and (org-list-first-item-p) (> delta 0))
(goto-char pos)
(error "Cannot indent the beginning of a sublist"))
;; 4. Do not outdent item that has children without moving
;; subtree. If moving subtree, the rule applies to its last
;; sub-item.
((and (< delta 0)
(save-excursion (goto-char (1- end)) (org-item-has-child-p)))
(goto-char pos)
(error "Cannot outdent an item having children")))))
;; Replace bullet of current item with the bullet it is going to
;; have if we're outdenting. This is needed to prevent indentation
;; problems of subtrees when outdenting changes bullet size.
(when (< delta 0)
(let ((new-bul (org-list-bullet-string (or bul-up bullet))))
(org-list-replace-bullet new-bul)))
;; Proceed to reindentation.
(while (< (point) end)
(beginning-of-line)
(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))
;; Get back to original position, shifted by delta
(goto-line line)
(move-to-column (max (+ delta col) 0))
;; Fix and reorder all lists and sublists from list at point. If
;; it has a parent and we're indenting, renumber parent too.
(save-excursion
;; Renumber parent list, if needed. No need for fixing bullets
(org-beginning-of-item-list)
(unless (or (< arg 0) (= (org-list-top-point) (point)))
(beginning-of-line 0)
(org-beginning-of-item)
(org-maybe-renumber-ordered-list)))
;; Take care of list at point. When demoting, to determine bullet
;; of children, follow, in order: `org-list-demote-modify-bullet',
;; same bullet as others children, same bullet as before
(org-fix-bullet-type
(and (> arg 0)
(or (cdr (assoc bullet org-list-demote-modify-bullet))
bul-down)))
(save-excursion
(when (org-item-has-child-p)
;; Take care of child, or of every sublist if we're moving a
;; subtree.
(org-end-of-item-or-at-child)
(if no-subtree
(org-fix-bullet-type)
(let ((fix-list (lambda (i)
(when (org-list-first-item-p)
(org-fix-bullet-type
(and (> arg 0)
(cdr (assoc (org-get-bullet) org-list-demote-modify-bullet)))))
(when (org-item-has-child-p)
(org-end-of-item-or-at-child)
(org-apply-on-list fix-list nil)))))
(org-apply-on-list fix-list nil))))))
;; Special case: moving top-item with indent rule
((and (= top beg) (cdr (assq 'indent org-list-automatic-rules)))
(let ((offset (if (< arg 0) -2 2))
(top-ind (nth 1 beg-item)))
(if (< (+ top-ind offset) 0)
(error "Cannot outdent beyond margin")
(when (and (= (+ top-ind offset) 0) (string-match "*" (nth 2 beg-item)))
(setcdr beg-item (list (nth 1 beg-item) (org-list-bullet-string "-"))))
(mapc '(lambda (item) (setcdr item (cons (+ (nth 1 item) offset) (cddr item)))) struct)
(org-list-struct-apply-struct struct))))
;; Forbidden move
((and (< arg 0)
(or (and no-subtree
(not (org-region-active-p))
(org-list-struct-get-child beg-item struct))
(org-list-struct-get-child end-item struct)))
(error "Cannot outdent an item without its children"))
;; Normal shifting
(t
(let* ((shifted-ori (if (< arg 0)
(org-list-struct-outdent beg end origins)
(org-list-struct-indent beg end origins))))
(org-list-struct-fix-struct struct shifted-ori)
(org-list-struct-apply-struct struct)))))
;; Return value
t)
(defun org-item-indent-positions ()
"Return indentations and bullets relatives to a plain list item.
This returns a list with three cons-cells containing indentation
and bullet of: the item, the item after a promotion, and the item
after being demoted. Assume cursor in item line."
(let* ((pos (point))
(init-bul (lambda (bullet)
(if (string-match "\\`[0-9]+\\(\\.\\|)\\)\\'" bullet)
(concat "1" (match-string 1 bullet))
bullet)))
;; Current item
(item-cur (cons (org-get-indentation)
(funcall init-bul (org-get-bullet))))
;; Parent
(item-up (save-excursion
(org-beginning-of-item-list)
(unless (= (org-list-top-point) (point))
(beginning-of-line 0)
(org-beginning-of-item)
(cons (org-get-indentation)
(funcall init-bul (org-get-bullet))))))
;; Child of previous item, if any.
(item-down (save-excursion
(let ((prev-p (org-get-previous-item (point) (save-excursion (org-beginning-of-item-list)))))
(cond
((and prev-p (goto-char prev-p) (org-item-has-child-p))
(progn
(org-end-of-item-or-at-child)
(cons (org-get-indentation)
(funcall init-bul (org-get-bullet)))))
((and (goto-char pos) (org-item-has-child-p))
(progn
(org-end-of-item-or-at-child)
(cons (org-get-indentation)
(funcall init-bul (org-get-bullet)))))
(t (org-at-item-p)
(goto-char (match-end 0))
(cons (current-column) (cdr item-cur))))))))
(list item-cur item-up item-down)))
(defvar org-tab-ind-state)
(defun org-cycle-item-indentation ()
(let ((org-adapt-indentation nil))
@ -996,21 +1177,34 @@ Assume cursor is at an item."
(and (looking-at "[ \t]*\\(\\S-+\\)") (match-string 1)))
(defun org-list-bullet-string (bullet)
"Concatenate BULLET with an appropriate number of whitespaces.
"Return BULLET with the correct number of whitespaces.
It determines the number of whitespaces to append by looking at
`org-list-two-spaces-after-bullet-regexp'."
(save-match-data
(concat
bullet " "
;; Do we need to concat another white space ?
(when (and org-list-two-spaces-after-bullet-regexp
(string-match org-list-two-spaces-after-bullet-regexp bullet))
" "))))
(string-match "\\S-+\\([ \t]*\\)" bullet)
(replace-match
(save-match-data
(concat
" "
;; Do we need to concat another white space ?
(when (and org-list-two-spaces-after-bullet-regexp
(string-match org-list-two-spaces-after-bullet-regexp bullet))
" ")))
nil nil bullet 1)))
(defun org-list-inc-bullet-maybe (bullet)
"Increment numbered bullets."
(if (string-match "[0-9]+" bullet)
(replace-match
(number-to-string (1+ (string-to-number (match-string 0 bullet)))) nil nil bullet)
bullet))
(defun org-list-replace-bullet (new-bullet)
"Replace current item's bullet with NEW-BULLET.
Assume point is at item. Indent body if needed."
Item body is re-indented, but sub-lists are not moved. Assume
point is at item."
(save-excursion
(beginning-of-line)
(let ((old (progn
(looking-at "[ \t]*\\(\\S-+[ \t]*\\)")
(match-string 1))))
@ -1018,58 +1212,34 @@ Assume point is at item. Indent body if needed."
(replace-match new-bullet nil nil nil 1)
;; When bullet lengths are differents, move the whole
;; sublist accordingly
(org-shift-item-indentation (- (length new-bullet) (length old)))))))
(org-shift-item-indentation
(- (length new-bullet) (length old)))))))
(defun org-fix-bullet-type (&optional force-bullet)
"Make sure all items in this list have the same bullet as the first item.
Also, fix the indentation."
(interactive)
(unless (org-at-item-p) (error "This is not a list"))
(org-preserve-lc
(let* ((ini-bul (progn (org-beginning-of-item-list) (org-get-bullet)))
(bullet (org-list-bullet-string (or force-bullet ini-bul)))
(replace-bullet
(lambda (result bullet)
(org-list-replace-bullet bullet))))
(org-apply-on-list replace-bullet nil bullet)
(org-maybe-renumber-ordered-list))))
(let* ((struct (org-list-struct (point-at-bol) (point-at-eol)))
(origins (org-list-struct-origins struct))
fixed-struct)
(if force-bullet
(let ((begin (nth 1 struct)))
(setcdr begin (list (nth 1 begin) (org-list-bullet-string force-bullet) (nth 3 begin)))
(setq fixed-struct (cons begin (org-list-struct-fix-struct struct origins))))
(setq fixed-struct (org-list-struct-fix-struct struct origins)))
(org-list-struct-apply-struct fixed-struct)))
(defun org-renumber-ordered-list (&optional arg)
(defun org-renumber-ordered-list ()
"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)\". Start to count at ARG or 1."
(interactive "p")
(save-match-data
(unless (and (org-at-item-p)
(match-beginning 3))
(error "This is not an ordered list"))
(org-preserve-lc
(let* ((item-fmt (progn
(looking-at "[ \t]*[0-9]+\\([.)]\\)")
(concat "%d" (or (match-string 1) "."))))
;; Here is the function applied at each item of the list.
(renumber-item (lambda (counter fmt)
(let* ((counter (or (save-excursion
(and (org-at-item-p)
(goto-char (match-end 0))
(looking-at "\\[@start:\\([0-9]+\\)\\]")
(string-to-number (match-string 1))))
counter))
(new (format fmt counter))
(old (progn
(looking-at org-item-beginning-re)
(match-string 2)))
(begin (match-beginning 2))
(end (match-end 2)))
(unless (equal new old)
(delete-region begin end)
(goto-char begin)
(insert new)
;; In case item number went from 9. to 10.
;; or the other way.
(org-shift-item-indentation (- (length new) (length old))))
(1+ counter)))))
(org-apply-on-list renumber-item (or arg 1) item-fmt)))))
Cursor needs to be in the first line of an item."
(interactive)
(unless (and (org-at-item-p)
(match-beginning 3))
(error "This is not an ordered list"))
(let* ((struct (org-list-struct (point-at-bol) (point-at-eol)))
(origins (org-list-struct-origins struct)))
(org-list-struct-apply-struct (org-list-struct-fix-struct struct origins))))
(defun org-maybe-renumber-ordered-list ()
"Renumber the ordered list at point if setup allows it.