I have a list of items.

* Heading 1
1. Item
2. Item

* Heading 2
1. Item
2. Item
3. Item

Is there an easy way to make the numbers run across the headings like this?

* Heading 1
1. Item
2. Item

* Heading 2
3. Item
4. Item
5. Item
  • Is Heading 2 a heading or a paragraph? That makes a big difference. There is no leading star before Heading 2.
    – Tobias
    Jun 15 '19 at 13:39
  • oops... there should be a leading star. Thanks!
    – Sati
    Jun 15 '19 at 13:54

It is possible to define the item number of any entry of a numbered list. For setting the item number to 3 one inserts [@3] between the item number and the item text.

If you apply that syntax in your example you get:

* Heading 1
1. Item
2. Item

* Heading 2
3. [@3] Item
4. Item
5. Item

Note that a similar question had been asked and answered on stackoverflow before.

The following Elisp code implements automatic item number continuation. Two numbers are given as cons in the new option org-list-continuation-marker.
The number in the car is the begin of the automatic number continuation range and the number in the cdr is a zero offset in this range.
Numbers given in the [@...] tag that are larger than the first entry of org-list-continuation-marker continue the numbering of the last list. The first item number of the continued list is that one of the last item of the last numbered list before plus the offset that results from [@...] entry minus the zero offset.

(defcustom org-list-continuation-marker '(900 . 1000)
  "Continue last list if the bullet counter is larger than
the car of this option.
In that case the next index is calculated as:
last index - counter + (cdr org-list-continuation-marker)."
  :type '(cons integer integer)
  :group 'org)

(defun my-org-list-last-bullet-counter (indent &optional point)
  "Get last bullet counter before POINT."
    (when point
      (goto-char point))
    (let (found current)
      (while (and (setq found (org-list-search-backward "^[[:space:]]\\([0-9]+\\)\\." nil t))
          (< indent (setq current (current-indentation)))))
      (when found
    (if (eq indent current)
        (string-to-number (match-string 1))

(defun my-org-list-struct-continue (struct &optional full-update)
  "Continue last enumeration.
Use this function as filter-return advice
of `org-list-struct' with STRUCT.
Fully update item number list if FULL-UPDATE is non-nil."
  (when (consp struct)
    (let ((counter (nth 3 (car struct)))
      (when (stringp counter)
    (setq counter (string-to-number counter))
    (when (>= counter (car org-list-continuation-marker))
      (setq last-counter (or (save-excursion
                   (goto-char (caar struct))
                   (my-org-list-last-bullet-counter (current-indentation)))
      (setq last-counter (+ last-counter counter (- (cdr org-list-continuation-marker))))
      (setf (nth 3 (car struct)) (number-to-string last-counter))
      ;; Adjusting the item numbers in advance is necessary in `org-list-struct-apply-struct'.
      (when full-update
        (dolist (item struct)
          (setf (nth 2 item) (replace-regexp-in-string "[0-9]+" (number-to-string last-counter) (nth 2 item)))
          (cl-incf last-counter)))

(defvar org-export-current-backend) ;; from ox.el

(defun my-ox-list-struct-continue-full (struct)
  "Export the same as `my-org-list-struct-continue' but with FULL-UPDATE."
  (if (bound-and-true-p org-export-current-backend)
    (my-org-list-struct-continue struct t)

;; `org-list-struct-apply-struct' is used for correcting item numbers in `org-ctrl-c-ctrl-c'.
(defun my-org-list-struct-apply-struct (args)
  "Continue last enumeration.
Use this function as filter-args advice for `org-list-struct-apply-struct'.
This function transforms argument list ARGS for `org-list-struct-apply-struct'."
  (cons (my-org-list-struct-continue (car args) t) (cdr args)))

(defun my-org-element-item-parser (fun _ struct &optional raw-secondary-p)
  "Automatically continue list item number in STRUCT."
  (let* ((info (funcall fun _ struct raw-secondary-p))
     (counter (org-element-property :counter info)))
    (when (and
       (bound-and-true-p org-export-current-backend)
       (numberp counter)
       (>= counter (car org-list-continuation-marker)))
      ;; We have done all the work in `my-ox-list-struct-continue-full'
      (let ((tag (nth 2 (car struct))))
    (when (string-match "[0-9]+" tag)
      (org-element-put-property info :counter (string-to-number (match-string 0 tag))))

(advice-add 'org-list-struct :filter-return #'my-org-list-struct-continue)

(advice-add 'org-element--list-struct :filter-return #'my-ox-list-struct-continue-full)

(advice-add 'org-element-item-parser :around #'my-org-element-item-parser)

(advice-add 'org-list-struct-apply-struct :filter-args #'my-org-list-struct-apply-struct)

We can apply the automatical continuation to your example in the following way with the standard settings for org-list-continuation-marker.

* Heading 1
1. Item
2. Item

* Heading 2
3. [@1001] Item
4. Item
5. Item

The following things are currently not automatic:

  • inserting a new item in the first list does not update the second list (that could be fixed by searching for the next numbered list and checking whether it is a continued list)

The following things are working:

  • C-c C-c on the second list updates it correctly
  • inserting a new item in the second list updates it correctly
  • exporting the org file uses the correctly updated item numbers

One could create a feature request for continued enumerated lists via org-submit-bug-report.

In that case I would propose to add the syntax [@+1] instead of [@1001], and [@-1] instead of [@999], for a continued item numbering.

With this syntax one could even intentionally leave one item number out by [@+2] in the middle of a numbered list. (That may make sense as placeholder.)

  • exporting to odt doesn't preserve the numbering. I currently have a quotation block across a numbered list .
    – Sati
    Jul 9 '19 at 7:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.