From: Rasmus <rasmus@gmx.us>
To: emacs-orgmode@gnu.org
Cc: alantyree@gmail.com, tsd@tsdye.com
Subject: Re: [patch, ox] Unnumbered headlines
Date: Sat, 20 Sep 2014 18:02:17 +0200 [thread overview]
Message-ID: <87k34y701i.fsf@gmx.us> (raw)
In-Reply-To: <87egwmaxte.fsf@nicolasgoaziou.fr> (Nicolas Goaziou's message of "Tue, 12 Aug 2014 10:58:53 +0200")
[-- Attachment #1: Type: text/plain, Size: 1699 bytes --]
Hi,
I'm happy to finally be able to send an updated version of this patch
that touches most backends in lisp/, but not the manual. I have been
moving over the summer etc.
You now specify unnumbered headlines with properties. I think this is
better since being unnumbered it's a pretty permanent state. It's
pretty hard to discover though, other than by looking at the output.
So this works as expected:
* Some headline
:PROPERTIES:
:UNNUMBERED: t
:END:
There's no :NUMBERED property and :UNNUMBERED is hardcoded.
I introduce a new function `org-export-get-headline-id` which returns
the first non-nil from the following list. There's a caveat:
CUSTOM_ID is ensured to be unique! Did I open the famous can of worm?
1. The CUSTOM_ID property.
2. A relative level number if the headline is numbered.
3. The ID property
4. A new generated unique ID.
Anyhow, `org-export-get-headline-id' ensures that we can refer to
unnumbered headlines, which was not possible before. Of course, in
LaTeX such ref to a \section* will be nonsense, so we could introduce
a \pageref here. I'm unsure about whether this conflicts
`org-latex-custom-id-as-label' which I had never seen until today
(also notes on this in patch).
I have updated backends in lisp/, but I'm at most(!) an "expert" on
LaTeX. However, I have tested all backends to the best of my ability.
Please feel free to test and let me know about any discrepancies!
Cheers,
Rasmus
PS: Not knowing or caring much about md, the links generated by it to
headlines seem wrong. Referring to headline 1 it only prints "1".
Should it be something like "[LABEL](1)"?
--
This is the kind of tedious nonsense up with which I will not put
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-ox-Support-unnumbered-headlines-via-property.patch --]
[-- Type: text/x-diff, Size: 14288 bytes --]
From fb44a552a151025513b645527498325febb6118f Mon Sep 17 00:00:00 2001
From: Rasmus <rasmus@gmx.us>
Date: Fri, 8 Aug 2014 14:53:01 +0200
Subject: [PATCH] ox: Support unnumbered headlines via property.
* ox.el (org-export--collect-headline-numbering): Return nil
if unnumbered headline.
(org-export-get-headline-id): New defun that returns a unique
ID to a headline.
(org-export-numbered-headline-p): Also tests for unnumbered
headline.
* ox-odt.el (org-odt-headline, org-odt-link,
org-odt-link--infer-description): Support unnumbered
headline.
* ox-md.el (org-md-headline, org-md-link): Support
unnumbered headlines.
* ox-latex.el (org-latex-headline, org.latex-link): Support
unnumbered headlines.
* ox-html.el (org-html-headline, org-html-link): Support
unnumbered headlines.
* ox-ascii.el (org-ascii-link): Support ununbered headlines.
Headlines can now be specified as unnumbered by assigning the property :UNUMBERED.
---
lisp/ox-ascii.el | 7 +++++--
lisp/ox-html.el | 22 ++++------------------
lisp/ox-latex.el | 22 ++--------------------
lisp/ox-md.el | 25 +++++++++++++------------
lisp/ox-odt.el | 32 ++++++++++++++++++--------------
lisp/ox.el | 44 ++++++++++++++++++++++++++++++++++++++++----
6 files changed, 82 insertions(+), 70 deletions(-)
diff --git a/lisp/ox-ascii.el b/lisp/ox-ascii.el
index 047b74e..8a5ad89 100644
--- a/lisp/ox-ascii.el
+++ b/lisp/ox-ascii.el
@@ -1511,9 +1511,12 @@ INFO is a plist holding contextual information."
(let ((number
(org-export-get-ordinal
destination info nil 'org-ascii--has-caption-p)))
- (when number
+ (if number
(if (atom number) (number-to-string number)
- (mapconcat 'number-to-string number "."))))))))
+ (mapconcat 'number-to-string number "."))
+ ;; unnumbered headline
+ (when (equal 'headline (org-element-type destination))
+ (format "[%s]" (org-export-data (org-export-get-alt-title destination info) info)))))))))
(t
(if (not (org-string-nw-p desc)) (format "[%s]" raw-link)
(concat (format "[%s]" desc)
diff --git a/lisp/ox-html.el b/lisp/ox-html.el
index 1d424cc..94cee20 100644
--- a/lisp/ox-html.el
+++ b/lisp/ox-html.el
@@ -2321,7 +2321,7 @@ holding contextual information."
(unless (org-element-property :footnote-section-p headline)
(let* ((numberedp (org-export-numbered-headline-p headline info))
(numbers (org-export-get-headline-number headline info))
- (section-number (mapconcat #'number-to-string numbers "-"))
+ (section-number (when numbers (mapconcat #'number-to-string numbers "-")))
(level (+ (org-export-get-relative-level headline info)
(1- (plist-get info :html-toplevel-hlevel))))
(todo (and (plist-get info :with-todo-keywords)
@@ -2338,9 +2338,9 @@ holding contextual information."
(contents (or contents ""))
(ids (delq nil
(list (org-element-property :CUSTOM_ID headline)
- (concat "sec-" section-number)
+ (when section-number (concat "sec-" section-number))
(org-element-property :ID headline))))
- (preferred-id (car ids))
+ (preferred-id (org-export-get-headline-id headline info))
(extra-ids (mapconcat
(lambda (id)
(org-html--anchor
@@ -2807,21 +2807,7 @@ INFO is a plist holding contextual information. See
(org-element-property :raw-link link) info))))
;; Link points to a headline.
(headline
- (let ((href
- ;; What href to use?
- (cond
- ;; Case 1: Headline is linked via it's CUSTOM_ID
- ;; property. Use CUSTOM_ID.
- ((string= type "custom-id")
- (org-element-property :CUSTOM_ID destination))
- ;; Case 2: Headline is linked via it's ID property
- ;; or through other means. Use the default href.
- ((member type '("id" "fuzzy"))
- (format "sec-%s"
- (mapconcat 'number-to-string
- (org-export-get-headline-number
- destination info) "-")))
- (t (error "Shouldn't reach here"))))
+ (let ((href (org-export-get-headline-id destination info))
;; What description to use?
(desc
;; Case 1: Headline is numbered and LINK has no
diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el
index f59d6b2..860b9f7 100644
--- a/lisp/ox-latex.el
+++ b/lisp/ox-latex.el
@@ -1476,15 +1476,7 @@ holding contextual information."
todo todo-type priority text tags info))
;; Associate \label to the headline for internal links.
(headline-label
- (let ((custom-label
- (and (plist-get info :latex-custom-id-labels)
- (org-element-property :CUSTOM_ID headline))))
- (if custom-label (format "\\label{%s}\n" custom-label)
- (format "\\label{sec-%s}\n"
- (mapconcat
- #'number-to-string
- (org-export-get-headline-number headline info)
- "-")))))
+ (format "\\label{%s}\n" (org-export-get-headline-id headline info)))
(pre-blanks
(make-string (org-element-property :pre-blank headline) 10)))
(if (or (not section-fmt) (org-export-low-level-p headline info))
@@ -1971,17 +1963,7 @@ INFO is a plist holding contextual information. See
;; number. Otherwise, display description or headline's
;; title.
(headline
- (let* ((custom-label
- (and (plist-get info :latex-custom-id-labels)
- (org-element-property :CUSTOM_ID destination)))
- (label
- (or
- custom-label
- (format "sec-%s"
- (mapconcat
- #'number-to-string
- (org-export-get-headline-number destination info)
- "-")))))
+ (let ((label (org-export-get-headline-id link info)))
(if (and (plist-get info :section-numbers) (not desc))
(format "\\ref{%s}" label)
(format "\\hyperref[%s]{%s}" label
diff --git a/lisp/ox-md.el b/lisp/ox-md.el
index 695fb61..383c629 100644
--- a/lisp/ox-md.el
+++ b/lisp/ox-md.el
@@ -202,12 +202,7 @@ a communication channel."
(and char (format "[#%c] " char)))))
(anchor
(when (plist-get info :with-toc)
- (org-html--anchor
- (or (org-element-property :CUSTOM_ID headline)
- (concat "sec-"
- (mapconcat 'number-to-string
- (org-export-get-headline-number
- headline info) "-")))
+ (org-html--anchor (org-export-get-headline-id headline info)
nil nil info)))
;; Headline text without tags.
(heading (concat todo priority title))
@@ -330,10 +325,12 @@ a communication channel."
(and contents (concat contents " "))
(format "(%s)"
(format (org-export-translate "See section %s" :html info)
- (mapconcat 'number-to-string
- (org-export-get-headline-number
- destination info)
- ".")))))))
+ (if (org-export-numbered-headline-p destination info)
+ (mapconcat 'number-to-string
+ (org-export-get-headline-number
+ destination info)
+ ".")
+ (org-export-get-alt-title headline info))))))))
((org-export-inline-image-p link org-html-inline-image-rules)
(let ((path (let ((raw-path (org-element-property :path link)))
(if (not (file-name-absolute-p raw-path)) raw-path
@@ -354,9 +351,13 @@ a communication channel."
(if (org-string-nw-p contents) contents
(when destination
(let ((number (org-export-get-ordinal destination info)))
- (when number
+ (if number
(if (atom number) (number-to-string number)
- (mapconcat 'number-to-string number "."))))))))
+ (mapconcat 'number-to-string number "."))
+ ;; unnumbered headline
+ (when (equal 'headline (org-element-type destination))
+ ;; BUG: shouldn't headlines have a form like [ref](name) in md
+ (org-export-data (org-export-get-alt-title destination info) info))))))))
;; Link type is handled by a special function.
((let ((protocol (nth 2 (assoc type org-link-protocols))))
(and (functionp protocol)
diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el
index 96a3b83..d5498ec 100644
--- a/lisp/ox-odt.el
+++ b/lisp/ox-odt.el
@@ -1816,12 +1816,15 @@ holding contextual information."
;; Get level relative to current parsed data.
(level (org-export-get-relative-level headline info))
;; Get canonical label for the headline.
- (id (concat "sec-" (mapconcat 'number-to-string
- (org-export-get-headline-number
- headline info) "-")))
+ (id (org-export-get-headline-id headline info))
;; Get user-specified labels for the headline.
- (extra-ids (list (org-element-property :CUSTOM_ID headline)
- (org-element-property :ID headline)))
+ (extra-ids (delq id (list
+ (org-element-property :CUSTOM_ID headline)
+ (org-element-property :ID headline)
+ (when (org-export-numbered-headline-p headline info)
+ (concat "sec-" (mapconcat 'number-to-string
+ (org-export-get-headline-number
+ headline info) "-"))))))
;; Extra targets.
(extra-targets
(mapconcat (lambda (x)
@@ -1870,9 +1873,13 @@ holding contextual information."
(t
(concat
(format
- "\n<text:h text:style-name=\"%s\" text:outline-level=\"%s\">%s</text:h>"
+ "\n<text:h text:style-name=\"%s\" text:outline-level=\"%s\" text:is-list-header=\"%s\">%s</text:h>"
(format "Heading_20_%s" level)
level
+ ;; text:is-list-header is how LO calls an unnumbered headline
+ ;; however, the definition here sounds weird:
+ ;; http://docs.oasis-open.org/office/v1.2/cs01/OpenDocument-v1.2-cs01-part1.html#__RefHeading__1415152_253892949
+ (if (org-export-numbered-headline-p headline info) "false" "true")
(concat extra-targets anchored-title))
contents))))))
@@ -2643,10 +2650,7 @@ Return nil, otherwise."
(let* ((genealogy (org-export-get-genealogy destination))
(data (reverse genealogy))
(label (case (org-element-type destination)
- (headline
- (format "sec-%s" (mapconcat 'number-to-string
- (org-export-get-headline-number
- destination info) "-")))
+ (headline (org-export-get-headline-id destination info))
(target
(org-element-property :value destination))
(t (error "FIXME: Resolve %S" destination)))))
@@ -2777,10 +2781,10 @@ INFO is a plist holding contextual information. See
;; Otherwise, try to provide a meaningful description.
(if (not desc) (org-odt-link--infer-description destination info)
(let* ((headline-no
- (org-export-get-headline-number destination info))
- (label
- (format "sec-%s"
- (mapconcat 'number-to-string headline-no "-"))))
+ (if (org-export-numbered-headline-p destination info)
+ (org-export-get-headline-number destination info)
+ (org-export-get-alt-title destination info)))
+ (label (org-export-get-headline-id destination info)))
(format
"<text:a xlink:type=\"simple\" xlink:href=\"#%s\">%s</text:a>"
label desc))))
diff --git a/lisp/ox.el b/lisp/ox.el
index f01f951..55c02eb 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -2003,7 +2003,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 options)))
(let ((relative-level
(1- (org-export-get-relative-level headline options))))
(cons
@@ -3807,6 +3808,40 @@ and the last level being considered as high enough, or nil."
(let ((level (org-export-get-relative-level headline info)))
(and (> level limit) (- level limit))))))
+(defun org-export-get-headline-id (headline info)
+ "Return a unique ID for HEADLINE.
+INFO is a plist holding contextual information.
+
+The method of generating the unique ID is as follows.
+ID is the first matching non-nil value of the following list:
+1. The CUSTOM_ID property.
+2. A relative level number if the headline is numbered.
+3. The ID property
+4. A new generated unique ID."
+ ;; FIX: this is seemingly incompatible (??) with
+ ;; `org-latex-custom-id-as-label'. However, it seems *no* similar
+ ;; variable exists for ox-html. Can be get drop `org-latex-custom-id-as-label'?
+ ;; Causal note: I have never touched this variable and yet custom_id works as expected.
+ ;; TODO: Better way is to check that CUSTOM_ID is unique? Or is that too intrusive?
+ (cond
+ ;; test if CUSTOM_ID exists and is unique
+ ((and (org-element-property :CUSTOM_ID headline)
+ (zerop (1- (length (org-element-map (plist-get info :parse-tree) 'headline
+ (lambda (otherhead)
+ (equal (org-element-property :CUSTOM_ID headline)
+ (org-element-property :CUSTOM_ID otherhead))))))))
+ (org-element-property :CUSTOM_ID headline))
+ ;; test if numbered and return sec-num string
+ ((org-export-numbered-headline-p headline info)
+ (format "sec-%s"
+ (mapconcat #'number-to-string
+ (org-export-get-headline-number headline info) "-")))
+ ;; return :ID and assign if necessary. Lasts for one export.
+ (t (and (or (org-element-property :ID headline)
+ (org-element-put-property
+ headline :ID (replace-regexp-in-string ":" "-" (org-id-new "sec"))))
+ (org-element-property :ID headline)))))
+
(defun org-export-get-headline-number (headline info)
"Return HEADLINE numbering as a list of numbers.
INFO is a plist holding contextual information."
@@ -3815,9 +3850,10 @@ 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))
- (level (org-export-get-relative-level headline info)))
- (if (wholenump sec-num) (<= level sec-num) sec-num)))
+ (unless (org-export-get-node-property :UNNUMBERED headline t)
+ (let ((sec-num (plist-get info :section-numbers))
+ (level (org-export-get-relative-level headline info)))
+ (if (wholenump sec-num) (<= level sec-num) sec-num)))))
(defun org-export-number-to-roman (n)
"Convert integer N into a roman numeral."
--
2.1.0
next prev parent reply other threads:[~2014-09-20 16:02 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-08 13:39 [patch, ox] Unnumbered headlines Rasmus
2014-08-08 22:35 ` Alan L Tyree
2014-08-09 1:04 ` [patch, ox] Unnumbered headlines - early test Alan L Tyree
2014-08-09 7:47 ` [patch, ox] Unnumbered headlines Detlef Steuer
2014-08-11 14:18 ` Nicolas Goaziou
2014-08-11 15:37 ` Rasmus
2014-08-12 8:58 ` Nicolas Goaziou
2014-09-20 16:02 ` Rasmus [this message]
2014-09-20 20:34 ` Alan L Tyree
2014-09-21 13:12 ` Nicolas Goaziou
2014-09-21 14:37 ` Rasmus
2014-09-21 19:40 ` Nicolas Goaziou
2014-09-21 20:13 ` Rasmus
2014-09-22 15:53 ` Nicolas Goaziou
2014-09-23 0:35 ` Rasmus
2014-09-23 1:10 ` Thomas S. Dye
2014-09-26 7:51 ` Nicolas Goaziou
2014-09-26 13:48 ` Rasmus
2014-09-27 8:19 ` Nicolas Goaziou
2014-09-30 22:54 ` Rasmus
2014-10-02 0:35 ` Rasmus
2014-10-03 7:56 ` Nicolas Goaziou
2014-10-03 8:49 ` Sebastien Vauban
2014-10-03 10:26 ` Rasmus
2014-10-03 20:14 ` Nicolas Goaziou
2014-10-03 20:31 ` Rasmus
2014-10-05 8:06 ` Nicolas Goaziou
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.orgmode.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87k34y701i.fsf@gmx.us \
--to=rasmus@gmx.us \
--cc=alantyree@gmail.com \
--cc=emacs-orgmode@gnu.org \
--cc=tsd@tsdye.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).