Hi,

In a recent thread¹ Tom and Alan mention that authors sometimes need
unnumbered headlines, e.g. for prefaces.  This patch (tries to) add
this feature via the tag :nonumber: (customizable via Custom or
in-file).

I make two assumptions.  First, the tag is recursive, so if the parent
is not numbered the child is not numbered.  Secondly, I depart from
the LaTeX tradition of ignoring unnumbered headlines in the TOC
(except in the case of ox-latex.el where it depends on
org-latex-classes).  (See example below).

Needless to say such a feature needs to be discussed and I not sure
whether the greater Org community finds it useful or needless clutter.

In my opinion a :nonumber: tag is a natural continuation of :export:
and :noexport: and unlike :ignoreheading: the implementation is fairly
clean (or maybe I'm cheating myself here).  A reason for why to
include it is that it seems relatively easy to do *during* export, but
it's hard to consistently get it right on in both headlines and the
TOC via filters.

The patch is messing with ox.el, and thus I would appreciate a review
and potentially testing, in the case that it is agreed that such a
feature would be OK to add to ox.

It seems to work well with ox-latex.el, ox-ascii.el and ox-html.el.
It doesn't play well with ox-odt.el (headlines are still numbered).  I
will fix this as well as adding documentation if a consensus of the
worthwhileness of the patch can be reached.

Finally, here's an example output using ox-ascii

#+begin_src org
    * a (not numbered)                :nonum:
    ** aa (not numbert)
    * b (1)
    ** ba (not numbered)              :nonum:
    *** baa (not numbered)
    ** bb (1.1)

#+end_src

#+RESULTS: (TOC only, but the rest is as expected)
    a (not numbered)
    .. aa (not numbert)
    1 b (1)
    .. ba (not numbered)
    ..... baa (not numbered)
    .. 1.1 bb (1.1)


Thanks,
Rasmus

Footnotes:
¹   http://permalink.gmane.org/gmane.emacs.orgmode/89515

--
Vote for proprietary math!
>From d38a728fef66af9df2a0b87e2126533961d87ecf Mon Sep 17 00:00:00 2001
From: Rasmus <ras...@gmx.us>
Date: Fri, 8 Aug 2014 14:53:01 +0200
Subject: [PATCH] ox.el: Support unnumbered headlines via tag.

* ox.el (org-export-options-alist): NO_NUMBER_TAGS new keyword.
(org-export-not-numbered-tags): New defcustom.
(org-export--collect-headline-numbering): Considers whether
headline is numbered.
(org-export-numbered-headline-p): Tests if headline is
to be numbered.
(org-export--recursive-tags): New function based.  Previouesly
part of `orge-export-get-tags'.
(org-export-get-tags): Ignoes NO_NUMBER_TAGS.
---
 lisp/ox.el | 60 +++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 43 insertions(+), 17 deletions(-)

diff --git a/lisp/ox.el b/lisp/ox.el
index d47c2e6..2fff14f 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -109,6 +109,7 @@
     (:language "LANGUAGE" nil org-export-default-language t)
     (:select-tags "SELECT_TAGS" nil org-export-select-tags split)
     (:exclude-tags "EXCLUDE_TAGS" nil org-export-exclude-tags split)
+    (:no-number-tags "NO_NUMBER_TAGS" nil org-export-not-numbered-tags split)
     (:creator "CREATOR" nil org-export-creator-string)
     (:headline-levels nil "H" org-export-headline-levels)
     (:preserve-breaks nil "\\n" org-export-preserve-breaks)
@@ -448,6 +449,18 @@ e.g. \"*:nil\"."
   :group 'org-export-general
   :type 'boolean)
 
+
+(defcustom org-export-not-numbered-tags '("nonumber")
+  "Tags that exclude trees from obtaining numbers.
+
+All trees carrying any of these tags will be excluded from
+receiving a number.  This includes subtress.
+
+This option can also be set in files with the NO_NUMBER_TAGS
+keyword."
+  :group 'org-export-general
+  :type '(repeat (string :tag "Tag")))
+
 (defcustom org-export-exclude-tags '("noexport")
   "Tags that exclude a tree from export.
 
@@ -1993,7 +2006,8 @@ for a footnotes section."
   (let ((numbering (make-vector org-export-max-depth 0)))
     (org-element-map data 'headline
       (lambda (headline)
-	(unless (org-element-property :footnote-section-p headline)
+	(unless (or (org-element-property :footnote-section-p headline)
+		    (not (org-export-numbered-headline-p headline info)))
 	  (let ((relative-level
 		 (1- (org-export-get-relative-level headline options))))
 	    (cons
@@ -3785,9 +3799,12 @@ INFO is a plist holding contextual information."
 (defun org-export-numbered-headline-p (headline info)
   "Return a non-nil value if HEADLINE element should be numbered.
 INFO is a plist used as a communication channel."
-  (let ((sec-num (plist-get info :section-numbers))
+  (let ((tags (org-export--recursive-tags headline info))
+	(sec-num (plist-get info :section-numbers))
 	(level (org-export-get-relative-level headline info)))
-    (if (wholenump sec-num) (<= level sec-num) sec-num)))
+    (unless (loop for k in (plist-get info :no-number-tags)
+		  thereis (member k tags))
+      (if (wholenump sec-num) (<= level sec-num) sec-num))))
 
 (defun org-export-number-to-roman (n)
   "Convert integer N into a roman numeral."
@@ -3805,14 +3822,33 @@ INFO is a plist used as a communication channel."
 	  (pop roman)))
       res)))
 
+(defun org-export--recursive-tags (element info)
+  "Return the full list of recursive tags associated with ELEMENT.
+
+ELEMENT has either an `headline' or an `inlinetask' type.  INFO
+is a plist used as a communication channel."
+  (let ((current-tag-list (org-element-property :tags element)))
+       (mapc
+	(lambda (parent)
+	  (mapc
+	   (lambda (tag)
+	     (when (and (memq (org-element-type parent) '(headline inlinetask))
+			(not (member tag current-tag-list)))
+	       (push tag current-tag-list)))
+	   (org-element-property :tags parent)))
+	(org-export-get-genealogy element))
+       ;; Add FILETAGS keywords and return results.
+       (org-uniquify (append (plist-get info :filetags) current-tag-list))))
+
 (defun org-export-get-tags (element info &optional tags inherited)
   "Return list of tags associated to ELEMENT.
 
 ELEMENT has either an `headline' or an `inlinetask' type.  INFO
 is a plist used as a communication channel.
 
-Select tags (see `org-export-select-tags') and exclude tags (see
-`org-export-exclude-tags') are removed from the list.
+Select tags (see `org-export-select-tags'), exclude tags (see
+`org-export-exclude-tags') and no-number tags (see
+`org-export-no-number-tags') are removed from the list.
 
 When non-nil, optional argument TAGS should be a list of strings.
 Any tag belonging to this list will also be removed.
@@ -3822,21 +3858,11 @@ inherited from parent headlines and FILETAGS keywords."
   (org-remove-if
    (lambda (tag) (or (member tag (plist-get info :select-tags))
 		(member tag (plist-get info :exclude-tags))
+		(member tag (plist-get info :no-number-tags))
 		(member tag tags)))
    (if (not inherited) (org-element-property :tags element)
      ;; Build complete list of inherited tags.
-     (let ((current-tag-list (org-element-property :tags element)))
-       (mapc
-	(lambda (parent)
-	  (mapc
-	   (lambda (tag)
-	     (when (and (memq (org-element-type parent) '(headline inlinetask))
-			(not (member tag current-tag-list)))
-	       (push tag current-tag-list)))
-	   (org-element-property :tags parent)))
-	(org-export-get-genealogy element))
-       ;; Add FILETAGS keywords and return results.
-       (org-uniquify (append (plist-get info :filetags) current-tag-list))))))
+     (org-export--recursive-tags (element info)))))
 
 (defun org-export-get-node-property (property blob &optional inherited)
   "Return node PROPERTY value for BLOB.
-- 
2.0.4

Reply via email to