Browse Source

org-list: implement alphabetical lists

* lisp/org-list.el (org-alphabetical-lists): new variable
(org-item-re, org-list-full-item, org-cycle-list-bullet,
org-list-struct-fix-bul, org-list-inc-bullet-maybe): reflect
introduction of the new variable.
(org-item-beginning-re): changed into a function, so any modification
of `org-alphabetical-lists' will not require reloading Org.
(org-at-item-p, org-toggle-checkbox, org-update-checkbox-count,
org-list-parse-list, org-list-send-list): reflect changes to
`org-item-beginning-re'.
(org-list-use-alpha-bul-p): new function.
* lisp/org.el (org-check-for-hidden): reflect changes to
`org-item-beginning-re'.
* lisp/org-capture.el (org-capture-place-item): reflect changes to
`org-item-beginning-re'.
* lisp/org-docbook.el (org-export-docbook-list-line): handle new type
of items.
* lisp/org-exp.el (org-export-mark-list-end,
org-export-mark-list-properties): reflect changes to
`org-item-beginning-re'.
* lisp/org-html.el (org-html-export-list-line): handle new type of
items.
* lisp/org-latex.el (org-export-latex-lists): handle new type of items
and reflect changes to `org-item-beginning-re'.
* lisp/org-ascii.el (org-export-ascii-preprocess): handle new counters.

Modified from a patch by Nathaniel Flath.
Nicolas Goaziou 8 years ago
parent
commit
781228183a
8 changed files with 224 additions and 81 deletions
  1. 2 1
      lisp/org-ascii.el
  2. 2 2
      lisp/org-capture.el
  3. 28 11
      lisp/org-docbook.el
  4. 4 4
      lisp/org-exp.el
  5. 26 7
      lisp/org-html.el
  6. 18 9
      lisp/org-latex.el
  7. 143 46
      lisp/org-list.el
  8. 1 1
      lisp/org.el

+ 2 - 1
lisp/org-ascii.el

@@ -577,7 +577,8 @@ publishing directory."
       (replace-match "\\1\\2")))
   ;; Remove list start counters
   (goto-char (point-min))
-  (while (org-list-search-forward "\\[@\\(?:start:\\)?[0-9]+\\][ \t]*" nil t)
+  (while (org-list-search-forward
+	  "\\[@\\(?:start:\\)?\\([0-9]+\\|[A-Za-z]\\)\\][ \t]*" nil t)
     (replace-match ""))
   (remove-text-properties
    (point-min) (point-max)

+ 2 - 2
lisp/org-capture.el

@@ -827,14 +827,14 @@ already gone.  Any prefix argument will be passed to the refile comand."
     (if (org-capture-get :prepend)
 	(progn
 	  (goto-char beg)
-	  (if (org-list-search-forward org-item-beginning-re end t)
+	  (if (org-list-search-forward (org-item-beginning-re) end t)
 	      (progn
 		(goto-char (match-beginning 0))
 		(setq ind (org-get-indentation)))
 	    (goto-char end)
 	    (setq ind 0)))
       (goto-char end)
-      (if (org-list-search-backward org-item-beginning-re beg t)
+      (if (org-list-search-backward (org-item-beginning-re) beg t)
 	  (progn
 	    (setq ind (org-get-indentation))
 	    (org-end-of-item))

+ 28 - 11
lisp/org-docbook.el

@@ -1341,7 +1341,7 @@ the alist of previous items."
 	   ;; "ordered", "variable" or "itemized".
 	   (lambda (pos)
 	     (cond
-	      ((string-match "[0-9]" (org-list-get-bullet pos struct))
+	      ((string-match "[[:alnum:]]" (org-list-get-bullet pos struct))
 	       "ordered")
 	      ((org-list-get-tag pos struct) "variable")
 	      (t "itemized")))))
@@ -1376,25 +1376,42 @@ the alist of previous items."
     (cond
      ;; At an item: insert appropriate tags in export buffer.
      ((assq pos struct)
-      (string-match
-       (concat "[ \t]*\\(\\(?:[-+*]\\|[0-9]+[.)]\\)[ \t]+\\)"
-	       "\\(?:\\[@\\(?:start:\\)?\\([0-9]+\\)\\]\\)?"
-	       "\\(?:\\(\\[[ X-]\\]\\)[ \t]+\\)?"
-	       "\\(?:\\(.*\\)[ \t]+::[ \t]+\\)?"
-	       "\\(.*\\)") line)
-      (let* ((counter (match-string 2 line))
-	     (checkbox (match-string 3 line))
+      (string-match (concat "[ \t]*\\(\\S-+[ \t]+\\)"
+			    "\\(?:\\[@\\(?:start:\\)?\\([0-9]+\\|[a-zA-Z]\\)\\]\\)?"
+			    "\\(?:\\(\\[[ X-]\\]\\)[ \t]+\\)?"
+			    "\\(?:\\(.*\\)[ \t]+::[ \t]+\\)?"
+			    "\\(.*\\)")
+		    line)
+      (let* ((checkbox (match-string 3 line))
 	     (desc-tag (or (match-string 4 line) "???"))
 	     (body (match-string 5 line))
 	     (list-beg (org-list-get-list-begin pos struct prevs))
 	     (firstp (= list-beg pos))
 	     ;; Always refer to first item to determine list type, in
 	     ;; case list is ill-formed.
-	     (type (funcall get-type list-beg)))
+	     (type (funcall get-type list-beg))
+	     ;; Special variables for ordered lists.
+	     (order-type (let ((bullet (org-list-get-bullet list-beg struct)))
+			   (cond
+			    ((not (equal type "ordered")) nil)
+			    ((string-match "[a-z]" bullet) "loweralpha")
+			    ((string-match "[A-Z]" bullet) "upperalpha")
+			    (t "arabic"))))
+	     (counter (let ((count-tmp (org-list-get-counter pos struct)))
+			(cond
+			 ((not count-tmp) nil)
+			 ((and (member order-type '("loweralpha" "upperalpha"))
+			       (string-match "[A-Za-z]" count-tmp))
+			  count-tmp)
+			 ((and (equal order-type "arabic")
+			       (string-match "[0-9]+" count-tmp))
+			  count-tmp)))))
 	;; When FIRSTP, a new list or sub-list is starting.
 	(when firstp
 	  (org-export-docbook-close-para-maybe)
-	  (insert (format "<%slist>\n" type)))
+	  (insert (if (equal type "ordered")
+		      (concat "<orderedlist numeration=\"" order-type "\">\n")
+		    (format "<%slist>\n" type))))
 	(insert (cond
 		 ((equal type "variable")
 		  (format "<varlistentry><term>%s</term><listitem>" desc-tag))

+ 4 - 4
lisp/org-exp.el

@@ -1682,11 +1682,11 @@ These special cookies will later be interpreted by the backend."
        ;; For each type allowing list export, find every list, remove
        ;; ending regexp if needed, and insert org-list-end.
        (goto-char (point-min))
-       (while (re-search-forward org-item-beginning-re nil t)
+       (while (re-search-forward (org-item-beginning-re) nil t)
 	 (when (eq (nth 2 (org-list-context)) e)
 	   (let* ((struct (org-list-struct))
 		  (bottom (org-list-get-bottom-point struct))
-		  (top (org-list-get-top-point struct))
+		  (top (point-at-bol))
 		  (top-ind (org-list-get-ind top struct)))
 	     (goto-char bottom)
 	     (when (and (not (eq org-list-ending-method 'indent))
@@ -1698,7 +1698,7 @@ These special cookies will later be interpreted by the backend."
 	     ;; there are lists within lists: the inner list end would
 	     ;; also become the outer list end. To avoid this, text
 	     ;; property `original-indentation' is added, as
-	     ;; `org-list-struct' pay attention to it when reading a
+	     ;; `org-list-struct' pays attention to it when reading a
 	     ;; list.
 	     (insert (org-add-props
 			 "ORG-LIST-END\n"
@@ -1763,7 +1763,7 @@ These special properties will later be interpreted by the backend."
 	(mapc
 	 (lambda (e)
 	   (goto-char (point-min))
-	   (while (re-search-forward org-item-beginning-re nil t)
+	   (while (re-search-forward (org-item-beginning-re) nil t)
 	     (when (eq (nth 2 (org-list-context)) e) (funcall mark-list e))))
 	 (cons nil org-list-export-context))))))
 

+ 26 - 7
lisp/org-html.el

@@ -2399,7 +2399,8 @@ the alist of previous items."
 	   ;; "o" or "u".
 	   (lambda (pos)
 	     (cond
-	      ((string-match "[0-9]" (org-list-get-bullet pos struct)) "o")
+	      ((string-match "[[:alnum:]]" (org-list-get-bullet pos struct))
+	       "o")
 	      ((org-list-get-tag pos struct) "d")
 	      (t "u")))))
 	 (get-closings
@@ -2432,23 +2433,41 @@ the alist of previous items."
      ;; At an item: insert appropriate tags in export buffer.
      ((assq pos struct)
       (string-match
-       (concat "[ \t]*\\(\\(?:[-+*]\\|[0-9]+[.)]\\)[ \t]+\\)"
-	       "\\(?:\\[@\\(?:start:\\)?\\([0-9]+\\)\\]\\)?"
+       (concat "[ \t]*\\(\\S-+[ \t]+\\)"
+	       "\\(?:\\[@\\(?:start:\\)?\\([0-9]+\\|[A-Za-z]\\)\\]\\)?"
 	       "\\(?:\\(\\[[ X-]\\]\\)[ \t]+\\)?"
 	       "\\(?:\\(.*\\)[ \t]+::[ \t]+\\)?"
 	       "\\(.*\\)") line)
-      (let* ((counter (match-string 2 line))
-	     (checkbox (match-string 3 line))
+      (let* ((checkbox (match-string 3 line))
 	     (desc-tag (or (match-string 4 line) "???"))
 	     (body (or (match-string 5 line) ""))
 	     (list-beg (org-list-get-list-begin pos struct prevs))
 	     (firstp (= list-beg pos))
 	     ;; Always refer to first item to determine list type, in
 	     ;; case list is ill-formed.
-	     (type (funcall get-type list-beg)))
+	     (type (funcall get-type list-beg))
+	     ;; Special variables for ordered lists.
+	     (order-type (let ((bullet (org-list-get-bullet list-beg struct)))
+			   (cond
+			    ((not (equal type "o")) nil)
+			    ((string-match "[a-z]" bullet) "a")
+			    ((string-match "[A-Z]" bullet) "A")
+			    (t "1"))))
+	     (counter (let ((count-tmp (org-list-get-counter pos struct)))
+			(cond
+			 ((not count-tmp) nil)
+			 ((and (member order-type '("a" "A"))
+			       (string-match "[A-Za-z]" count-tmp))
+			  (- (string-to-char (upcase count-tmp)) 64))
+			 ((and (equal order-type "1")
+			       (string-match "[0-9]+" count-tmp))
+			  count-tmp)))))
 	(when firstp
 	  (org-close-par-maybe)
-	  (insert (format "<%sl>\n" type)))
+	  ;; Treat ordered lists differently because of ORDER-TYPE.
+	  (insert (if (equal type "o")
+		      (concat "<ol type=\"" order-type "\">\n")
+		    (format "<%sl>\n" type))))
 	(insert (cond
 		 ((equal type "d")
 		  (format "<dt>%s</dt><dd>\n" desc-tag))

+ 18 - 9
lisp/org-latex.el

@@ -2467,7 +2467,7 @@ The conversion is made depending of STRING-BEFORE and STRING-AFTER."
      ;; conversion to latex (RES).
      (let (res)
        (goto-char (point-min))
-       (while (re-search-forward org-item-beginning-re nil t)
+       (while (re-search-forward (org-item-beginning-re) nil t)
 	 (when (and (eq (get-text-property (point) 'list-context) e)
 		    (not (get-text-property (point) 'org-example)))
 	   (beginning-of-line)
@@ -2483,16 +2483,25 @@ The conversion is made depending of STRING-BEFORE and STRING-AFTER."
 		      (org-list-parse-list t)))
 		  org-export-latex-list-parameters))
 	   ;; Replace any counter with its latex expression in string.
+           ;;
+	   ;; FIXME: enumi is for top list only. Sub-lists are using
+	   ;;        enumii, enumiii, enumiv. So, basically, using a
+	   ;;        counter within a sublist will break top-level
+	   ;;        item numbering.
 	   (while (string-match
-		   "^\\(\\\\item[ \t]+\\)\\[@\\(?:start:\\)?\\([0-9]+\\)\\]"
+		   "^\\(\\\\item[ \t]+\\)\\[@\\(?:start:\\)?\\([0-9]+\\|[A-Z-a-z]\\)\\]"
 		   res)
-	     (setq res (replace-match
-			(concat (format "\\setcounter{enumi}{%d}"
-					(1- (string-to-number
-					     (match-string 2 res))))
-				"\n"
-				(match-string 1 res))
-			t t res)))
+	     (let ((count (match-string 2 res)))
+	       (setq res (replace-match
+			  (concat
+			   ;; Filter out non-numeric counters,
+			   ;; unsupported in standard LaTeX.
+			   (if (save-match-data (string-match "[0-9]" count))
+			       (format "\\setcounter{enumi}{%d}\n"
+				       (1- (string-to-number count)))
+			     "")
+			   (match-string 1 res))
+			  t t res))))
 	   ;; Extend previous value of original-indentation to the
 	   ;; whole string
 	   (insert (org-add-props res nil 'original-indentation

+ 143 - 46
lisp/org-list.el

@@ -177,6 +177,13 @@ the safe choice."
 		 (const :tag "paren like in \"2)\"" ?\))
 		 (const :tab "both" t)))
 
+(defcustom org-alphabetical-lists nil
+  "Non-nil means single character alphabetical bullets are allowed.
+Both uppercase and lowercase are handled. Lists with more than 26
+items will fallback to standard numbering."
+  :group 'org-plain-lists
+  :type 'boolean)
+
 (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.
@@ -319,25 +326,24 @@ specifically, type `block' is determined by the variable
   "Regex corresponding to the end of a list.
 It depends on `org-empty-line-terminates-plain-lists'.")
 
-(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]+\\*\\)\\([ \t]+\\|$\\)")
-   ((= org-plain-list-ordered-item-terminator ?.)
-    "\\([ \t]*\\([-+]\\|\\([0-9]+\\.\\)\\)\\|[ \t]+\\*\\)\\([ \t]+\\|$\\)")
-   ((= org-plain-list-ordered-item-terminator ?\))
-    "\\([ \t]*\\([-+]\\|\\([0-9]+)\\)\\)\\|[ \t]+\\*\\)\\([ \t]+\\|$\\)")
-   (t (error "Invalid value of `org-plain-list-ordered-item-terminator'"))))
-
-(defconst org-item-beginning-re (concat "^" (org-item-re))
-  "Regexp matching the beginning of a plain list item.")
+(defun org-item-re ()
+  "Return the correct regular expression for plain lists."
+  (let ((term (cond
+	       ((eq org-plain-list-ordered-item-terminator t) "[.)]")
+	       ((= org-plain-list-ordered-item-terminator ?\)) ")")
+	       ((= org-plain-list-ordered-item-terminator ?.) "\\.")
+	       (t "[.)]")))
+	(alpha (if org-alphabetical-lists "\\|[A-Za-z]" "")))
+    (concat "\\([ \t]*\\([-+]\\|\\(\\([0-9]+" alpha "\\)" term
+	    "\\)\\)\\|[ \t]+\\*\\)\\([ \t]+\\|$\\)")))
+
+(defun org-item-beginning-re ()
+  "Regexp matching the beginning of a plain list item."
+  (concat "^" (org-item-re)))
 
 (defconst org-list-full-item-re
-  (concat "^[ \t]*\\(\\(?:[-+*]\\|[0-9]+[.)]\\)[ \t]+\\)"
-	  "\\(?:\\[@\\(?:start:\\)?\\([0-9]+\\)\\]\\)?"
+  (concat "^[ \t]*\\(\\(?:[-+*]\\|\\(?:[0-9]+\\|[A-Za-z]\\)[.)]\\)[ \t]+\\)"
+	  "\\(?:\\[@\\(?:start:\\)?\\([0-9]+\\|[A-Za-z]\\)\\]\\)?"
 	  "\\(?:\\(\\[[ X-]\\]\\)[ \t]+\\)?"
 	  "\\(?:\\(.*\\)[ \t]+::[ \t]+\\)?")
   "Matches a list item and puts everything into groups:
@@ -778,7 +784,7 @@ This checks `org-list-ending-method'."
 
 (defun org-at-item-p ()
   "Is point in a line starting a hand-formatted item?"
-  (save-excursion (beginning-of-line) (looking-at org-item-beginning-re)))
+  (save-excursion (beginning-of-line) (looking-at (org-item-beginning-re))))
 
 (defun org-at-item-bullet-p ()
   "Is point at the bullet of a plain list item?"
@@ -1445,8 +1451,12 @@ PREVS is the alist of previous items. See
 `org-list-struct-prev-alist'.
 
 This function modifies STRUCT."
-  (let ((fix-bul
+  (let ((case-fold-search nil)
+	(fix-bul
 	 (function
+	  ;; Set bullet of ITEM in STRUCT, depending on the type of
+	  ;; first item of the list, the previous bullet and counter
+	  ;; if any.
 	  (lambda (item)
 	    (let* ((prev (org-list-get-prev-item item struct prevs))
 		   (prev-bul (and prev (org-list-get-bullet prev struct)))
@@ -1456,14 +1466,51 @@ This function modifies STRUCT."
 	       item struct
 	       (org-list-bullet-string
 		(cond
-		 ((and prev (string-match "[0-9]+" prev-bul) counter)
+		 ;; Alpha counter in alpha list: use counter.
+		 ((and prev counter
+		       (string-match "[a-zA-Z]" counter)
+		       (string-match "[a-zA-Z]" prev-bul))
+		  ;; Use cond to be sure `string-match' is used in
+		  ;; both cases.
+		  (let ((real-count
+			 (cond
+			  ((string-match "[a-z]" prev-bul) (downcase counter))
+			  ((string-match "[A-Z]" prev-bul) (upcase counter)))))
+		    (replace-match real-count nil nil prev-bul)))
+		 ;; Num counter in a num list: use counter.
+		 ((and prev counter
+		       (string-match "[0-9]+" counter)
+		       (string-match "[0-9]+" prev-bul))
 		  (replace-match counter nil nil prev-bul))
+		 ;; No counter: increase, if needed, previous bullet.
 		 (prev
 		  (org-list-inc-bullet-maybe (org-list-get-bullet prev struct)))
-		 ((and (string-match "[0-9]+" bullet) counter)
+		 ;; Alpha counter at first item: use counter.
+		 ((and counter (org-list-use-alpha-bul-p item struct prevs)
+		       (string-match "[A-Za-z]" counter)
+		       (string-match "[A-Za-z]" bullet))
+		  (let ((real-count
+			 (cond
+			  ((string-match "[a-z]" bullet) (downcase counter))
+			  ((string-match "[A-Z]" bullet) (upcase counter)))))
+		    (replace-match real-count nil nil bullet)))
+		 ;; Num counter at first item: use counter.
+		 ((and counter
+		       (string-match "[0-9]+" counter)
+		       (string-match "[0-9]+" bullet))
 		  (replace-match counter nil nil bullet))
-		 ((string-match "[0-9]+" bullet)
+		 ;; First bullet is alpha uppercase: use "A".
+		 ((and (org-list-use-alpha-bul-p item struct prevs)
+		       (string-match "[A-Z]" bullet))
+		  (replace-match "A" nil nil bullet))
+		 ;; First bullet is alpha lowercase: use "a".
+		 ((and (org-list-use-alpha-bul-p item struct prevs)
+		       (string-match "[a-z]" bullet))
+		  (replace-match "a" nil nil bullet))
+		 ;; First bullet is num: use "1".
+		 ((string-match "\\([0-9]+\\|[A-Za-z]\\)" bullet)
 		  (replace-match "1" nil nil bullet))
+		 ;; Not an ordered list: keep bullet.
 		 (t bullet)))))))))
     (mapc fix-bul (mapcar 'car struct))))
 
@@ -1911,13 +1958,47 @@ It determines the number of whitespaces to append by looking at
           " ")))
      nil nil bullet 1)))
 
+(defun org-list-use-alpha-bul-p (first struct prevs)
+  "Can list starting at FIRST use alphabetical bullets?
+
+STRUCT is list structure. See `org-list-struct'. PREVS is the
+alist of previous items. See `org-list-struct-prev-alist'."
+  (and org-alphabetical-lists
+       (catch 'exit
+	 (let ((item first) (ascii 64) (case-fold-search nil))
+	   ;; Pretend that bullets are uppercase and checked if
+	   ;; alphabet is sufficient, taking counters into account.
+	   (while item
+	     (let ((bul (org-list-get-bullet item struct))
+		   (count (org-list-get-counter item struct)))
+	       ;; Virtually determine current bullet
+	       (if (and count (string-match "[a-zA-Z]" count))
+		   ;; Counters are not case-sensitive.
+		   (setq ascii (string-to-char (upcase count)))
+		 (setq ascii (1+ ascii)))
+	       ;; Test if bullet would be over z or Z.
+	       (if (> ascii 90)
+		   (throw 'exit nil)
+		 (setq item (org-list-get-next-item item struct prevs)))))
+	   ;; All items checked. All good.
+	   t))))
+
 (defun org-list-inc-bullet-maybe (bullet)
   "Increment BULLET if applicable."
-  (if (string-match "[0-9]+" bullet)
+  (let ((case-fold-search nil))
+    (cond
+     ;; Num bullet: increment it.
+     ((string-match "[0-9]+" bullet)
       (replace-match
        (number-to-string (1+ (string-to-number (match-string 0 bullet))))
-       nil nil bullet)
-    bullet))
+       nil nil bullet))
+     ;; Alpha bullet: increment it.
+     ((string-match "[A-Za-z]" bullet)
+      (replace-match
+       (char-to-string (1+ (string-to-char (match-string 0 bullet))))
+       nil nil bullet))
+     ;; Unordered bullet: leave it.
+     (t bullet))))
 
 (defun org-list-repair ()
   "Make sure all items are correctly indented, with the right bullet.
@@ -1944,25 +2025,40 @@ is an integer, 0 means `-', 1 means `+' etc. If WHICH is
     (let* ((struct (org-list-struct))
            (parents (org-list-struct-parent-alist struct))
            (prevs (org-list-struct-prev-alist struct))
-           (list-beg (org-list-get-list-begin (point) struct prevs))
+           (list-beg (org-list-get-first-item (point) struct prevs))
            (bullet (org-list-get-bullet list-beg struct))
+	   (bullet-rule-p (cdr (assq 'bullet org-list-automatic-rules)))
+	   (alpha-p (org-list-use-alpha-bul-p list-beg struct prevs))
+	   (case-fold-search nil)
 	   (current (cond
+		     ((string-match "[a-z]\\." bullet) "a.")
+		     ((string-match "[a-z])" bullet) "a)")
+		     ((string-match "[A-Z]\\." bullet) "A.")
+		     ((string-match "[A-Z])" bullet) "A)")
 		     ((string-match "\\." bullet) "1.")
 		     ((string-match ")" bullet) "1)")
 		     (t (org-trim bullet))))
-	   (bullet-rule-p (cdr (assq 'bullet org-list-automatic-rules)))
            ;; Compute list of possible bullets, depending on context
-	   (bullet-list (append '("-" "+" )
-				;; *-bullets are not allowed at column 0
-				(unless (and bullet-rule-p
-					     (looking-at "\\S-")) '("*"))
-				;; Description items cannot be numbered
-				(unless (and bullet-rule-p
-					     (or (eq org-plain-list-ordered-item-terminator ?\))
-						 (org-at-item-description-p))) '("1."))
-				(unless (and bullet-rule-p
-					     (or (eq org-plain-list-ordered-item-terminator ?.)
-						 (org-at-item-description-p))) '("1)"))))
+	   (bullet-list
+	    (append '("-" "+" )
+		    ;; *-bullets are not allowed at column 0
+		    (unless (and bullet-rule-p
+				 (looking-at "\\S-")) '("*"))
+		    ;; Description items cannot be numbered
+		    (unless (or (eq org-plain-list-ordered-item-terminator ?\))
+				(and bullet-rule-p (org-at-item-description-p)))
+		      '("1."))
+		    (unless (or (eq org-plain-list-ordered-item-terminator ?.)
+				(and bullet-rule-p (org-at-item-description-p)))
+		      '("1)"))
+		    (unless (or (not alpha-p)
+				(eq org-plain-list-ordered-item-terminator ?\))
+				(and bullet-rule-p (org-at-item-description-p)))
+		      '("a." "A."))
+		    (unless (or (not alpha-p)
+				(eq org-plain-list-ordered-item-terminator ?.)
+				(and bullet-rule-p (org-at-item-description-p)))
+		      '("a)" "A)"))))
 	   (len (length bullet-list))
 	   (item-index (- len (length (member current bullet-list))))
 	   (get-value (lambda (index) (nth (mod index len) bullet-list)))
@@ -2006,7 +2102,7 @@ in subtree, ignoring drawers."
 	     ((org-region-active-p)
 	      (let ((limit (region-end)))
 		(goto-char (region-beginning))
-		(if (org-list-search-forward org-item-beginning-re limit t)
+		(if (org-list-search-forward (org-item-beginning-re) limit t)
 		    (setq lim-up (point-at-bol))
 		  (error "No item in region"))
 		(setq lim-down (copy-marker limit))))
@@ -2016,7 +2112,7 @@ in subtree, ignoring drawers."
 		(forward-line 1)
 		(when (looking-at org-drawer-regexp)
 		  (re-search-forward "^[ \t]*:END:" limit nil))
-		(if (org-list-search-forward org-item-beginning-re limit t)
+		(if (org-list-search-forward (org-item-beginning-re) limit t)
 		    (setq lim-up (point-at-bol))
 		  (error "No item in subtree"))
 		(setq lim-down (copy-marker limit))))
@@ -2044,7 +2140,7 @@ in subtree, ignoring drawers."
       ;; list; 3. move point after the list.
       (goto-char lim-up)
       (while (and (< (point) lim-down)
-		  (org-list-search-forward org-item-beginning-re
+		  (org-list-search-forward (org-item-beginning-re)
 					   lim-down 'move))
 	(let* ((struct (org-list-struct))
 	       (struct-copy (mapcar (lambda (e) (copy-alist e)) struct))
@@ -2118,7 +2214,7 @@ With optional prefix argument ALL, do this for the whole buffer."
   (interactive "P")
   (save-excursion
     (let ((cookie-re "\\(\\(\\[[0-9]*%\\]\\)\\|\\(\\[[0-9]*/[0-9]*\\]\\)\\)")
-	  (box-re "^[ \t]*\\([-+*]\\|[0-9]+[.)]\\)[ \t]+\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\(\\[[- X]\\]\\)")
+	  (box-re "^[ \t]*\\([-+*]\\|\\([0-9]+\\|[A-Za-z]\\)[.)]\\)[ \t]+\\(?:\\[@\\(?:start:\\)?\\([0-9]+\\|[A-Za-z]\\)\\][ \t]*\\)?\\(\\[[- X]\\]\\)")
 	  (recursivep
 	   (or (not org-hierarchical-checkbox-statistics)
 	       (string-match "\\<recursive\\>"
@@ -2410,7 +2506,8 @@ Point is left at list end."
 	   ;; determine type of list by getting info on item POS in
 	   ;; STRUCT.
 	   (lambda (pos struct)
-	     (cond ((string-match "[0-9]" (org-list-get-bullet pos struct))
+	     (cond ((string-match "[[:alnum:]]"
+				  (org-list-get-bullet pos struct))
 		    'ordered)
 		   ((org-list-get-tag pos struct) 'descriptive)
 		   (t 'unordered)))))
@@ -2428,7 +2525,7 @@ Point is left at list end."
 	   (lambda (e)
 	     (let ((start (save-excursion
 			    (goto-char e)
-			    (looking-at org-item-beginning-re)
+			    (looking-at (org-item-beginning-re))
 			    (match-end 0)))
 		   (childp (org-list-has-child-p e struct))
 		   (end (org-list-get-item-end e struct)))
@@ -2455,7 +2552,7 @@ Point is left at list end."
 	     (let ((text (org-trim (buffer-substring beg end))))
 	       (if (and box
 			(string-match
-			 "^\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\([xX ]\\)\\]"
+			 "^\\(?:\\[@\\(?:start:\\)?\\(?:[0-9]+\\|[A-Za-z]\\)\\][ \t]*\\)?\\[\\([xX ]\\)\\]"
 			 text))
 		   (replace-match
 		    (if (equal (match-string 1 text) " ") "CBOFF" "CBON")
@@ -2535,7 +2632,7 @@ this list."
 	   (top-point
 	    (progn
 	      (re-search-backward "#\\+ORGLST" nil t)
-	      (re-search-forward org-item-beginning-re bottom-point t)
+	      (re-search-forward (org-item-beginning-re) bottom-point t)
 	      (match-beginning 0)))
 	   (list (save-restriction
 		   (narrow-to-region top-point bottom-point)

+ 1 - 1
lisp/org.el

@@ -17064,7 +17064,7 @@ an outline or item heading and it has a folded subtree below it,
 this function returns t, nil otherwise."
   (let ((re (cond
 	     ((eq what 'headlines) (concat "^" org-outline-regexp))
-	     ((eq what 'items) (concat "^" (org-item-re t)))
+	     ((eq what 'items) (org-item-beginning-re))
 	     (t (error "This should not happen"))))
 	beg end)
     (save-excursion