Forráskód Böngészése

Merge branch 'master' of orgmode.org:org-mode

Bastien Guerry 10 éve
szülő
commit
9c64957609

+ 1 - 1
contrib/lisp/ox-koma-letter.el

@@ -222,7 +222,7 @@ This option can also be set with the OPTIONS keyword, e.g.:
   :type 'boolean)
   :type 'boolean)
 
 
 (defcustom org-koma-letter-subject-format t
 (defcustom org-koma-letter-subject-format t
-  "Use the title as the subject of the letter.
+  "When non-nil include subject.  Supports formatting options.
 
 
 When t, insert a subject using default options.  When nil, do not
 When t, insert a subject using default options.  When nil, do not
 insert a subject at all.  It can also be a list of symbols among
 insert a subject at all.  It can also be a list of symbols among

+ 17 - 0
doc/org.texi

@@ -10008,6 +10008,23 @@ to use the obvious defaults.
 #+INCLUDE: "~/.emacs" :lines "10-"    @r{Include lines from 10 to EOF}
 #+INCLUDE: "~/.emacs" :lines "10-"    @r{Include lines from 10 to EOF}
 @end example
 @end example
 
 
+Finally, you may use a file-link to extract an object as matched by
+@code{org-link-search}@footnote{Note that
+@code{org-link-search-must-match-exact-headline} is locally bound to non-nil.
+Therefore, @code{org-link-search} only matches headlines and named elements.}
+(@pxref{Search options}).  If the @code{:only-contents} property is non-nil,
+only the contents of the requested element will be included, omitting
+properties drawer and planning-line if present.  The @code{:lines} keyword
+operates locally with respect to the requested element.  Some examples:
+
+@example
+#+INCLUDE: "./paper.org::#theory" :only-contents t
+   @r{Include the body of the heading with the custom id @code{theory}}
+#+INCLUDE: "./paper.org::mytable"  @r{Include named element.}
+#+INCLUDE: "./paper.org::*conclusion" :lines 1-20
+   @r{Include the first 20 lines of the headline named conclusion.}
+@end example
+
 @table @kbd
 @table @kbd
 @kindex C-c '
 @kindex C-c '
 @item C-c '
 @item C-c '

+ 7 - 2
doc/orgguide.texi

@@ -2264,8 +2264,13 @@ include your @file{.emacs} file, you could use:
 The optional second and third parameter are the markup (i.e., @samp{example}
 The optional second and third parameter are the markup (i.e., @samp{example}
 or @samp{src}), and, if the markup is @samp{src}, the language for formatting
 or @samp{src}), and, if the markup is @samp{src}, the language for formatting
 the contents.  The markup is optional, if it is not given, the text will be
 the contents.  The markup is optional, if it is not given, the text will be
-assumed to be in Org mode format and will be processed normally. @kbd{C-c '}
-will visit the included file.
+assumed to be in Org mode format and will be processed normally.  File-links
+will be interpreted as well:
+@smallexample
+#+INCLUDE: "./otherfile.org::#my_custom_id" :only-contents t
+@end smallexample
+@noindent
+@kbd{C-c '} will visit the included file.
 
 
 @node Embedded @LaTeX{},  , Include files, Markup
 @node Embedded @LaTeX{},  , Include files, Markup
 @section Embedded @LaTeX{}
 @section Embedded @LaTeX{}

+ 19 - 0
etc/styles/OrgOdtStyles.xml

@@ -109,33 +109,52 @@
   </style:style>
   </style:style>
   <style:style style:name="Heading_20_1" style:display-name="Heading 1" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="1" style:class="text">
   <style:style style:name="Heading_20_1" style:display-name="Heading 1" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="1" style:class="text">
    <style:text-properties fo:font-size="115%" fo:font-weight="bold" style:font-size-asian="115%" style:font-weight-asian="bold" style:font-size-complex="115%" style:font-weight-complex="bold"/>
    <style:text-properties fo:font-size="115%" fo:font-weight="bold" style:font-size-asian="115%" style:font-weight-asian="bold" style:font-size-complex="115%" style:font-weight-complex="bold"/>
+   <style:style style:name="Heading_20_1_unnumbered" style:family="paragraph" style:parent-style-name="Heading_20_1" style:list-style-name="">
   </style:style>
   </style:style>
   <style:style style:name="Heading_20_2" style:display-name="Heading 2" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="2" style:class="text">
   <style:style style:name="Heading_20_2" style:display-name="Heading 2" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="2" style:class="text">
    <style:text-properties fo:font-size="14pt" fo:font-style="italic" fo:font-weight="bold" style:font-size-asian="14pt" style:font-style-asian="italic" style:font-weight-asian="bold" style:font-size-complex="14pt" style:font-style-complex="italic" style:font-weight-complex="bold"/>
    <style:text-properties fo:font-size="14pt" fo:font-style="italic" fo:font-weight="bold" style:font-size-asian="14pt" style:font-style-asian="italic" style:font-weight-asian="bold" style:font-size-complex="14pt" style:font-style-complex="italic" style:font-weight-complex="bold"/>
+  </style:style>
+    <style:style style:name="Heading_20_2_unnumbered" style:family="paragraph" style:parent-style-name="Heading_20_2" style:list-style-name="">
   </style:style>
   </style:style>
   <style:style style:name="Heading_20_3" style:display-name="Heading 3" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="3" style:class="text">
   <style:style style:name="Heading_20_3" style:display-name="Heading 3" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="3" style:class="text">
    <style:text-properties fo:font-size="14pt" fo:font-weight="bold" style:font-size-asian="14pt" style:font-weight-asian="bold" style:font-size-complex="14pt" style:font-weight-complex="bold"/>
    <style:text-properties fo:font-size="14pt" fo:font-weight="bold" style:font-size-asian="14pt" style:font-weight-asian="bold" style:font-size-complex="14pt" style:font-weight-complex="bold"/>
+  </style:style>
+    <style:style style:name="Heading_20_3_unnumbered" style:family="paragraph" style:parent-style-name="Heading_20_3" style:list-style-name="">
   </style:style>
   </style:style>
   <style:style style:name="Heading_20_4" style:display-name="Heading 4" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="4" style:class="text">
   <style:style style:name="Heading_20_4" style:display-name="Heading 4" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="4" style:class="text">
    <style:text-properties fo:font-size="85%" fo:font-style="italic" fo:font-weight="bold" style:font-size-asian="85%" style:font-style-asian="italic" style:font-weight-asian="bold" style:font-size-complex="85%" style:font-style-complex="italic" style:font-weight-complex="bold"/>
    <style:text-properties fo:font-size="85%" fo:font-style="italic" fo:font-weight="bold" style:font-size-asian="85%" style:font-style-asian="italic" style:font-weight-asian="bold" style:font-size-complex="85%" style:font-style-complex="italic" style:font-weight-complex="bold"/>
+  </style:style>
+    <style:style style:name="Heading_20_4_unnumbered" style:family="paragraph" style:parent-style-name="Heading_20_4" style:list-style-name="">
   </style:style>
   </style:style>
   <style:style style:name="Heading_20_5" style:display-name="Heading 5" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="5" style:class="text">
   <style:style style:name="Heading_20_5" style:display-name="Heading 5" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="5" style:class="text">
    <style:text-properties fo:font-size="85%" fo:font-weight="bold" style:font-size-asian="85%" style:font-weight-asian="bold" style:font-size-complex="85%" style:font-weight-complex="bold"/>
    <style:text-properties fo:font-size="85%" fo:font-weight="bold" style:font-size-asian="85%" style:font-weight-asian="bold" style:font-size-complex="85%" style:font-weight-complex="bold"/>
+  </style:style>
+    <style:style style:name="Heading_20_5_unnumbered" style:family="paragraph" style:parent-style-name="Heading_20_5" style:list-style-name="">
   </style:style>
   </style:style>
   <style:style style:name="Heading_20_6" style:display-name="Heading 6" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="6" style:class="text">
   <style:style style:name="Heading_20_6" style:display-name="Heading 6" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="6" style:class="text">
    <style:text-properties fo:font-size="75%" fo:font-weight="bold" style:font-size-asian="75%" style:font-weight-asian="bold" style:font-size-complex="75%" style:font-weight-complex="bold"/>
    <style:text-properties fo:font-size="75%" fo:font-weight="bold" style:font-size-asian="75%" style:font-weight-asian="bold" style:font-size-complex="75%" style:font-weight-complex="bold"/>
+  </style:style>
+    <style:style style:name="Heading_20_6_unnumbered" style:family="paragraph" style:parent-style-name="Heading_20_6" style:list-style-name="">
   </style:style>
   </style:style>
   <style:style style:name="Heading_20_7" style:display-name="Heading 7" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="7" style:class="text">
   <style:style style:name="Heading_20_7" style:display-name="Heading 7" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="7" style:class="text">
    <style:text-properties fo:font-size="75%" fo:font-weight="bold" style:font-size-asian="75%" style:font-weight-asian="bold" style:font-size-complex="75%" style:font-weight-complex="bold"/>
    <style:text-properties fo:font-size="75%" fo:font-weight="bold" style:font-size-asian="75%" style:font-weight-asian="bold" style:font-size-complex="75%" style:font-weight-complex="bold"/>
+  </style:style>
+    <style:style style:name="Heading_20_7_unnumbered" style:family="paragraph" style:parent-style-name="Heading_20_7" style:list-style-name="">
   </style:style>
   </style:style>
   <style:style style:name="Heading_20_8" style:display-name="Heading 8" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="8" style:class="text">
   <style:style style:name="Heading_20_8" style:display-name="Heading 8" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="8" style:class="text">
    <style:text-properties fo:font-size="75%" fo:font-weight="bold" style:font-size-asian="75%" style:font-weight-asian="bold" style:font-size-complex="75%" style:font-weight-complex="bold"/>
    <style:text-properties fo:font-size="75%" fo:font-weight="bold" style:font-size-asian="75%" style:font-weight-asian="bold" style:font-size-complex="75%" style:font-weight-complex="bold"/>
+  </style:style>
+    <style:style style:name="Heading_20_8_unnumbered" style:family="paragraph" style:parent-style-name="Heading_20_8" style:list-style-name="">
   </style:style>
   </style:style>
   <style:style style:name="Heading_20_9" style:display-name="Heading 9" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="9" style:class="text">
   <style:style style:name="Heading_20_9" style:display-name="Heading 9" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="9" style:class="text">
    <style:text-properties fo:font-size="75%" fo:font-weight="bold" style:font-size-asian="75%" style:font-weight-asian="bold" style:font-size-complex="75%" style:font-weight-complex="bold"/>
    <style:text-properties fo:font-size="75%" fo:font-weight="bold" style:font-size-asian="75%" style:font-weight-asian="bold" style:font-size-complex="75%" style:font-weight-complex="bold"/>
   </style:style>
   </style:style>
+    <style:style style:name="Heading_20_9_unnumbered" style:family="paragraph" style:parent-style-name="Heading_20_9" style:list-style-name="">
+    </style:style>
   <style:style style:name="Heading_20_10" style:display-name="Heading 10" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="10" style:class="text">
   <style:style style:name="Heading_20_10" style:display-name="Heading 10" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="10" style:class="text">
    <style:text-properties fo:font-size="75%" fo:font-weight="bold" style:font-size-asian="75%" style:font-weight-asian="bold" style:font-size-complex="75%" style:font-weight-complex="bold"/>
    <style:text-properties fo:font-size="75%" fo:font-weight="bold" style:font-size-asian="75%" style:font-weight-asian="bold" style:font-size-complex="75%" style:font-weight-complex="bold"/>
+  </style:style>
+    <style:style style:name="Heading_20_10_unnumbered" style:family="paragraph" style:parent-style-name="Heading_20_10" style:list-style-name="">
   </style:style>
   </style:style>
   <style:style style:name="Heading_20_1.title" style:display-name="Heading 1.title" style:family="paragraph" style:parent-style-name="Heading_20_1">
   <style:style style:name="Heading_20_1.title" style:display-name="Heading 1.title" style:family="paragraph" style:parent-style-name="Heading_20_1">
    <style:paragraph-properties fo:text-align="center" style:justify-single-word="false"/>
    <style:paragraph-properties fo:text-align="center" style:justify-single-word="false"/>

+ 8 - 2
lisp/ob-table.el

@@ -47,7 +47,10 @@
 ;; |        7 |        |
 ;; |        7 |        |
 ;; |        8 |        |
 ;; |        8 |        |
 ;; |        9 |        |
 ;; |        9 |        |
-;; #+TBLFM: $2='(org-sbe 'fibbd (n $1))
+;; #+TBLFM: $2='(org-sbe "fibbd" (n $1))
+
+;; NOTE: The quotation marks around the function name, 'fibbd' here,
+;; are optional.
 
 
 ;;; Code:
 ;;; Code:
 (require 'ob-core)
 (require 'ob-core)
@@ -69,7 +72,7 @@ string of its value.
 
 
 So this `org-sbe' construct
 So this `org-sbe' construct
 
 
- (org-sbe 'source-block (n $2) (m 3))
+ (org-sbe \"source-block\" (n $2) (m 3))
 
 
 is the equivalent of the following source code block:
 is the equivalent of the following source code block:
 
 
@@ -77,6 +80,9 @@ is the equivalent of the following source code block:
  results
  results
  #+end_src
  #+end_src
 
 
+NOTE: The quotation marks around the function name,
+'source-block', are optional.
+
 NOTE: By default, string variable names are interpreted as
 NOTE: By default, string variable names are interpreted as
 references to source-code blocks, to force interpretation of a
 references to source-code blocks, to force interpretation of a
 cell's value as a string, prefix the identifier a \"$\" (e.g.,
 cell's value as a string, prefix the identifier a \"$\" (e.g.,

+ 12 - 4
lisp/org.el

@@ -15340,7 +15340,7 @@ but in some other way.")
     "LOCATION" "LOGGING" "COLUMNS" "VISIBILITY"
     "LOCATION" "LOGGING" "COLUMNS" "VISIBILITY"
     "TABLE_EXPORT_FORMAT" "TABLE_EXPORT_FILE"
     "TABLE_EXPORT_FORMAT" "TABLE_EXPORT_FILE"
     "EXPORT_OPTIONS" "EXPORT_TEXT" "EXPORT_FILE_NAME"
     "EXPORT_OPTIONS" "EXPORT_TEXT" "EXPORT_FILE_NAME"
-    "EXPORT_TITLE" "EXPORT_AUTHOR" "EXPORT_DATE"
+    "EXPORT_TITLE" "EXPORT_AUTHOR" "EXPORT_DATE" "UNNUMBERED"
     "ORDERED" "NOBLOCKING" "COOKIE_DATA" "LOG_INTO_DRAWER" "REPEAT_TO_STATE"
     "ORDERED" "NOBLOCKING" "COOKIE_DATA" "LOG_INTO_DRAWER" "REPEAT_TO_STATE"
     "CLOCK_MODELINE_TOTAL" "STYLE" "HTML_CONTAINER_CLASS")
     "CLOCK_MODELINE_TOTAL" "STYLE" "HTML_CONTAINER_CLASS")
   "Some properties that are used by Org-mode for various purposes.
   "Some properties that are used by Org-mode for various purposes.
@@ -20525,9 +20525,17 @@ Otherwise, return a user error."
 		       session params))))))
 		       session params))))))
       (keyword
       (keyword
        (if (member (org-element-property :key element) '("INCLUDE" "SETUPFILE"))
        (if (member (org-element-property :key element) '("INCLUDE" "SETUPFILE"))
-           (find-file-other-window
-            (org-remove-double-quotes
-             (car (org-split-string (org-element-property :value element)))))
+           (org-open-link-from-string
+	    (format "[[%s]]"
+		    (expand-file-name
+		     (let ((value (org-element-property :value element)))
+		       (cond ((not (org-string-nw-p value))
+			      (user-error "No file to edit"))
+			     ((string-match "\\`\"\\(.*?\\)\"" value)
+			      (match-string 1 value))
+			     ((string-match "\\`[^ \t\"]\\S-*" value)
+			      (match-string 0 value))
+			     (t (user-error "No valid file specified")))))))
          (user-error "No special environment to edit here")))
          (user-error "No special environment to edit here")))
       (table
       (table
        (if (eq (org-element-property :type element) 'table.el)
        (if (eq (org-element-property :type element) 'table.el)

+ 6 - 2
lisp/ox-ascii.el

@@ -1530,9 +1530,13 @@ INFO is a plist holding contextual information."
 	    (let ((number
 	    (let ((number
 		   (org-export-get-ordinal
 		   (org-export-get-ordinal
 		    destination info nil 'org-ascii--has-caption-p)))
 		    destination info nil 'org-ascii--has-caption-p)))
-	      (when number
+	      (if number
 		(if (atom number) (number-to-string number)
 		(if (atom number) (number-to-string number)
-		  (mapconcat 'number-to-string number "."))))))))
+		  (mapconcat #'number-to-string number "."))
+		;; Unnumbered headline.
+		(when (eq 'headline (org-element-type destination))
+		  (format "[%s]" (org-export-data
+				  (org-element-property :title destination) info)))))))))
      (t
      (t
       (if (not (org-string-nw-p desc)) (format "[%s]" raw-link)
       (if (not (org-string-nw-p desc)) (format "[%s]" raw-link)
 	(concat (format "[%s]" desc)
 	(concat (format "[%s]" desc)

+ 15 - 24
lisp/ox-html.el

@@ -2096,8 +2096,7 @@ INFO is a plist used as a communication channel."
 	    ;; Label.
 	    ;; Label.
 	    (org-export-solidify-link-text
 	    (org-export-solidify-link-text
 	     (or (org-element-property :CUSTOM_ID headline)
 	     (or (org-element-property :CUSTOM_ID headline)
-		 (concat "sec-"
-			 (mapconcat #'number-to-string headline-number "-"))))
+		 (org-export-get-headline-id headline info)))
 	    ;; Body.
 	    ;; Body.
 	    (concat
 	    (concat
 	     (and (not (org-export-low-level-p headline info))
 	     (and (not (org-export-low-level-p headline info))
@@ -2321,7 +2320,8 @@ holding contextual information."
   (unless (org-element-property :footnote-section-p headline)
   (unless (org-element-property :footnote-section-p headline)
     (let* ((numberedp (org-export-numbered-headline-p headline info))
     (let* ((numberedp (org-export-numbered-headline-p headline info))
            (numbers (org-export-get-headline-number headline info))
            (numbers (org-export-get-headline-number headline info))
-           (section-number (mapconcat #'number-to-string numbers "-"))
+           (section-number (and numbers
+				(mapconcat #'number-to-string numbers "-")))
            (level (+ (org-export-get-relative-level headline info)
            (level (+ (org-export-get-relative-level headline info)
                      (1- (plist-get info :html-toplevel-hlevel))))
                      (1- (plist-get info :html-toplevel-hlevel))))
            (todo (and (plist-get info :with-todo-keywords)
            (todo (and (plist-get info :with-todo-keywords)
@@ -2338,7 +2338,7 @@ holding contextual information."
            (contents (or contents ""))
            (contents (or contents ""))
            (ids (delq nil
            (ids (delq nil
                       (list (org-element-property :CUSTOM_ID headline)
                       (list (org-element-property :CUSTOM_ID headline)
-                            (concat "sec-" section-number)
+                            (org-export-get-headline-id headline info)
                             (org-element-property :ID headline))))
                             (org-element-property :ID headline))))
            (preferred-id (car ids))
            (preferred-id (car ids))
            (extra-ids (mapconcat
            (extra-ids (mapconcat
@@ -2369,7 +2369,7 @@ holding contextual information."
                   (org-html--container headline info)
                   (org-html--container headline info)
                   (format "outline-container-%s"
                   (format "outline-container-%s"
                           (or (org-element-property :CUSTOM_ID headline)
                           (or (org-element-property :CUSTOM_ID headline)
-                              (concat "sec-" section-number)))
+                              (org-export-get-headline-id headline info)))
                   (concat (format "outline-%d" level)
                   (concat (format "outline-%d" level)
                           (and extra-class " ")
                           (and extra-class " ")
                           extra-class)
                           extra-class)
@@ -2807,21 +2807,9 @@ INFO is a plist holding contextual information.  See
 			(org-element-property :raw-link link) info))))
 			(org-element-property :raw-link link) info))))
 	  ;; Link points to a headline.
 	  ;; Link points to a headline.
 	  (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 (or (and (string= type "custom-id")
+				(org-element-property :CUSTOM_ID destination))
+			   (org-export-get-headline-id destination info)))
 		 ;; What description to use?
 		 ;; What description to use?
 		 (desc
 		 (desc
 		  ;; Case 1: Headline is numbered and LINK has no
 		  ;; Case 1: Headline is numbered and LINK has no
@@ -3073,13 +3061,16 @@ holding contextual information."
       (let* ((class-num (+ (org-export-get-relative-level parent info)
       (let* ((class-num (+ (org-export-get-relative-level parent info)
 			   (1- (plist-get info :html-toplevel-hlevel))))
 			   (1- (plist-get info :html-toplevel-hlevel))))
 	     (section-number
 	     (section-number
-	      (mapconcat
-	       'number-to-string
-	       (org-export-get-headline-number parent info) "-")))
+	      (and (org-export-numbered-headline-p parent info)
+		   (mapconcat
+		    #'number-to-string
+		    (org-export-get-headline-number parent info) "-"))))
         ;; Build return value.
         ;; Build return value.
 	(format "<div class=\"outline-text-%d\" id=\"text-%s\">\n%s</div>"
 	(format "<div class=\"outline-text-%d\" id=\"text-%s\">\n%s</div>"
 		class-num
 		class-num
-		(or (org-element-property :CUSTOM_ID parent) section-number)
+		(or (org-element-property :CUSTOM_ID parent)
+		    section-number
+		    (org-export-get-headline-id parent info))
 		contents)))))
 		contents)))))
 
 
 ;;;; Radio Target
 ;;;; Radio Target

+ 6 - 17
lisp/ox-latex.el

@@ -1477,15 +1477,10 @@ holding contextual information."
 			       todo todo-type priority text tags info))
 			       todo todo-type priority text tags info))
 	   ;; Associate \label to the headline for internal links.
 	   ;; Associate \label to the headline for internal links.
 	   (headline-label
 	   (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"
+		    (or (and (plist-get info :latex-custom-id-labels)
+			     (org-element-property :CUSTOM_ID headline))
+			(org-export-get-headline-id headline info))))
 	   (pre-blanks
 	   (pre-blanks
 	    (make-string (org-element-property :pre-blank headline) 10)))
 	    (make-string (org-element-property :pre-blank headline) 10)))
       (if (or (not section-fmt) (org-export-low-level-p headline info))
       (if (or (not section-fmt) (org-export-low-level-p headline info))
@@ -1975,14 +1970,8 @@ INFO is a plist holding contextual information.  See
 	   (let* ((custom-label
 	   (let* ((custom-label
 		   (and (plist-get info :latex-custom-id-labels)
 		   (and (plist-get info :latex-custom-id-labels)
 			(org-element-property :CUSTOM_ID destination)))
 			(org-element-property :CUSTOM_ID destination)))
-		  (label
-		   (or
-		    custom-label
-		    (format "sec-%s"
-			    (mapconcat
-			     #'number-to-string
-			     (org-export-get-headline-number destination info)
-			     "-")))))
+		  (label (or custom-label
+			     (org-export-get-headline-id destination info))))
 	     (if (and (not desc)
 	     (if (and (not desc)
 		      (org-export-numbered-headline-p destination info))
 		      (org-export-numbered-headline-p destination info))
 		 (format "\\ref{%s}" label)
 		 (format "\\ref{%s}" label)

+ 16 - 11
lisp/ox-md.el

@@ -204,10 +204,7 @@ a communication channel."
 	    (when (plist-get info :with-toc)
 	    (when (plist-get info :with-toc)
 	      (org-html--anchor
 	      (org-html--anchor
 	       (or (org-element-property :CUSTOM_ID headline)
 	       (or (org-element-property :CUSTOM_ID headline)
-		   (concat "sec-"
-			   (mapconcat 'number-to-string
-				      (org-export-get-headline-number
-				       headline info) "-")))
+		   (org-export-get-headline-id headline info))
 	       nil nil info)))
 	       nil nil info)))
 	   ;; Headline text without tags.
 	   ;; Headline text without tags.
 	   (heading (concat todo priority title))
 	   (heading (concat todo priority title))
@@ -330,10 +327,13 @@ a communication channel."
 	   (and contents (concat contents " "))
 	   (and contents (concat contents " "))
 	   (format "(%s)"
 	   (format "(%s)"
 		   (format (org-export-translate "See section %s" :html info)
 		   (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-data
+			      (org-element-property :title destination) info))))))))
      ((org-export-inline-image-p link org-html-inline-image-rules)
      ((org-export-inline-image-p link org-html-inline-image-rules)
       (let ((path (let ((raw-path (org-element-property :path link)))
       (let ((path (let ((raw-path (org-element-property :path link)))
 		    (if (not (file-name-absolute-p raw-path)) raw-path
 		    (if (not (file-name-absolute-p raw-path)) raw-path
@@ -354,9 +354,14 @@ a communication channel."
 	(if (org-string-nw-p contents) contents
 	(if (org-string-nw-p contents) contents
 	  (when destination
 	  (when destination
 	    (let ((number (org-export-get-ordinal destination info)))
 	    (let ((number (org-export-get-ordinal destination info)))
-	      (when number
-		(if (atom number) (number-to-string number)
-		  (mapconcat 'number-to-string number "."))))))))
+	      (if number
+		  (if (atom number) (number-to-string number)
+		    (mapconcat #'number-to-string number "."))
+		;; Unnumbered headline.
+		(and (eq 'headline (org-element-type destination))
+		     ;; BUG: shouldn't headlines have a form like [ref](name) in md?
+		     (org-export-data
+		      (org-element-property :title destination) info))))))))
      ;; Link type is handled by a special function.
      ;; Link type is handled by a special function.
      ((let ((protocol (nth 2 (assoc type org-link-protocols))))
      ((let ((protocol (nth 2 (assoc type org-link-protocols))))
 	(and (functionp protocol)
 	(and (functionp protocol)

+ 22 - 24
lisp/ox-odt.el

@@ -1122,7 +1122,7 @@ See `org-odt--build-date-styles' for implementation details."
   (setq text
   (setq text
 	(concat
 	(concat
 	 ;; Section number.
 	 ;; Section number.
-	 (when section-number (concat section-number ". "))
+	 (and section-number (concat section-number ". "))
 	 ;; Todo.
 	 ;; Todo.
 	 (when todo
 	 (when todo
 	   (let ((style (if (member todo org-done-keywords)
 	   (let ((style (if (member todo org-done-keywords)
@@ -1789,8 +1789,7 @@ INFO is a plist holding contextual information."
 		(org-element-property :title headline) backend info))
 		(org-element-property :title headline) backend info))
 	 (tags (and (plist-get info :with-tags)
 	 (tags (and (plist-get info :with-tags)
 		    (org-export-get-tags headline info)))
 		    (org-export-get-tags headline info)))
-	 (headline-label (concat "sec-" (mapconcat 'number-to-string
-						   headline-number "-")))
+	 (headline-label (org-export-get-headline-id headline info))
 	 (format-function
 	 (format-function
 	  (if (functionp format-function) format-function
 	  (if (functionp format-function) format-function
 	    (function*
 	    (function*
@@ -1815,10 +1814,9 @@ holding contextual information."
 	   (full-text (org-odt-format-headline--wrap headline nil info))
 	   (full-text (org-odt-format-headline--wrap headline nil info))
 	   ;; Get level relative to current parsed data.
 	   ;; Get level relative to current parsed data.
 	   (level (org-export-get-relative-level headline info))
 	   (level (org-export-get-relative-level headline info))
+	   (numbered (org-export-numbered-headline-p headline info))
 	   ;; Get canonical label for the headline.
 	   ;; 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.
 	   ;; Get user-specified labels for the headline.
 	   (extra-ids (list (org-element-property :CUSTOM_ID headline)
 	   (extra-ids (list (org-element-property :CUSTOM_ID headline)
 			    (org-element-property :ID headline)))
 			    (org-element-property :ID headline)))
@@ -1842,8 +1840,7 @@ holding contextual information."
 	 (and (org-export-first-sibling-p headline info)
 	 (and (org-export-first-sibling-p headline info)
 	      (format "\n<text:list text:style-name=\"%s\" %s>"
 	      (format "\n<text:list text:style-name=\"%s\" %s>"
 		      ;; Choose style based on list type.
 		      ;; Choose style based on list type.
-		      (if (org-export-numbered-headline-p headline info)
-			  "OrgNumberedList" "OrgBulletedList")
+		      (if numbered "OrgNumberedList" "OrgBulletedList")
 		      ;; If top-level list, re-start numbering.  Otherwise,
 		      ;; If top-level list, re-start numbering.  Otherwise,
 		      ;; continue numbering.
 		      ;; continue numbering.
 		      (format "text:continue-numbering=\"%s\""
 		      (format "text:continue-numbering=\"%s\""
@@ -1870,9 +1867,11 @@ holding contextual information."
        (t
        (t
 	(concat
 	(concat
 	 (format
 	 (format
-	  "\n<text:h text:style-name=\"%s\" text:outline-level=\"%s\">%s</text:h>"
-	  (format "Heading_20_%s" level)
+	  "\n<text:h text:style-name=\"%s\" text:outline-level=\"%s\" text:is-list-header=\"%s\">%s</text:h>"
+	  (format "Heading_20_%s%s"
+		  level (if numbered "" "_unnumbered"))
 	  level
 	  level
+	  (if numbered "false" "true")
 	  (concat extra-targets anchored-title))
 	  (concat extra-targets anchored-title))
 	 contents))))))
 	 contents))))))
 
 
@@ -2643,10 +2642,7 @@ Return nil, otherwise."
   (let* ((genealogy (org-export-get-genealogy destination))
   (let* ((genealogy (org-export-get-genealogy destination))
 	 (data (reverse genealogy))
 	 (data (reverse genealogy))
 	 (label (case (org-element-type destination)
 	 (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
 		  (target
 		   (org-element-property :value destination))
 		   (org-element-property :value destination))
 		  (t (error "FIXME: Resolve %S" destination)))))
 		  (t (error "FIXME: Resolve %S" destination)))))
@@ -2692,11 +2688,15 @@ Return nil, otherwise."
 			      item-numbers "")))))
 			      item-numbers "")))))
      ;; Case 2: Locate a regular and numbered headline in the
      ;; Case 2: Locate a regular and numbered headline in the
      ;; hierarchy.  Display its section number.
      ;; hierarchy.  Display its section number.
-     (let ((headline (loop for el in (cons destination genealogy)
-			   when (and (eq (org-element-type el) 'headline)
-				     (not (org-export-low-level-p el info))
-				     (org-export-numbered-headline-p el info))
-			   return el)))
+     (let ((headline
+	    (and
+	     ;; Test if destination is a numbered headline.
+	     (org-export-numbered-headline-p destination info)
+	     (loop for el in (cons destination genealogy)
+		   when (and (eq (org-element-type el) 'headline)
+			     (not (org-export-low-level-p el info))
+			     (org-export-numbered-headline-p el info))
+		   return el))))
        ;; We found one.
        ;; We found one.
        (when headline
        (when headline
 	 (format "<text:bookmark-ref text:reference-format=\"chapter\" text:ref-name=\"OrgXref.%s\">%s</text:bookmark-ref>"
 	 (format "<text:bookmark-ref text:reference-format=\"chapter\" text:ref-name=\"OrgXref.%s\">%s</text:bookmark-ref>"
@@ -2776,11 +2776,9 @@ INFO is a plist holding contextual information.  See
 	   ;; If there's a description, create a hyperlink.
 	   ;; If there's a description, create a hyperlink.
 	   ;; Otherwise, try to provide a meaningful description.
 	   ;; Otherwise, try to provide a meaningful description.
 	   (if (not desc) (org-odt-link--infer-description destination info)
 	   (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 "-"))))
+	     (let ((label (or (and (string= type "custom-id")
+				   (org-element-property :CUSTOM_ID destination))
+			      (org-export-get-headline-id destination info))))
 	       (format
 	       (format
 		"<text:a xlink:type=\"simple\" xlink:href=\"#%s\">%s</text:a>"
 		"<text:a xlink:type=\"simple\" xlink:href=\"#%s\">%s</text:a>"
 		label desc))))
 		label desc))))

+ 148 - 18
lisp/ox.el

@@ -1974,6 +1974,7 @@ Return updated plist."
   ;; properties.
   ;; properties.
   (nconc
   (nconc
    `(:headline-numbering ,(org-export--collect-headline-numbering data info)
    `(:headline-numbering ,(org-export--collect-headline-numbering data info)
+     :unnumbered-headline-id ,(org-export--collect-unnumbered-headline-id data info)
      :exported-data ,(make-hash-table :test 'eq :size 4001))
      :exported-data ,(make-hash-table :test 'eq :size 4001))
    info))
    info))
 
 
@@ -1996,7 +1997,7 @@ OPTIONS is a plist holding export options."
       (if (= min-level 10000) 1 min-level))))
       (if (= min-level 10000) 1 min-level))))
 
 
 (defun org-export--collect-headline-numbering (data options)
 (defun org-export--collect-headline-numbering (data options)
-  "Return numbering of all exportable headlines in a parse tree.
+  "Return numbering of all exportable, numbered headlines in a parse tree.
 
 
 DATA is the parse tree.  OPTIONS is the plist holding export
 DATA is the parse tree.  OPTIONS is the plist holding export
 options.
 options.
@@ -2007,7 +2008,8 @@ for a footnotes section."
   (let ((numbering (make-vector org-export-max-depth 0)))
   (let ((numbering (make-vector org-export-max-depth 0)))
     (org-element-map data 'headline
     (org-element-map data 'headline
       (lambda (headline)
       (lambda (headline)
-	(unless (org-element-property :footnote-section-p headline)
+	(when (and (org-export-numbered-headline-p headline options)
+		   (not (org-element-property :footnote-section-p headline)))
 	  (let ((relative-level
 	  (let ((relative-level
 		 (1- (org-export-get-relative-level headline options))))
 		 (1- (org-export-get-relative-level headline options))))
 	    (cons
 	    (cons
@@ -2019,6 +2021,17 @@ for a footnotes section."
 		   when (> idx relative-level) do (aset numbering idx 0))))))
 		   when (> idx relative-level) do (aset numbering idx 0))))))
       options)))
       options)))
 
 
+(defun org-export--collect-unnumbered-headline-id (data options)
+  "Return numbering of all exportable, unnumbered headlines.
+DATA is the parse tree.  OPTIONS is the plist holding export
+options.  Unnumbered headlines are numbered as a function of
+occurrence."
+  (let ((num 0))
+    (org-element-map data 'headline
+	(lambda (headline)
+	  (unless (org-export-numbered-headline-p headline options)
+	    (list headline (incf num)))))))
+
 (defun org-export--populate-ignore-list (data options)
 (defun org-export--populate-ignore-list (data options)
   "Return list of elements and objects to ignore during export.
   "Return list of elements and objects to ignore during export.
 DATA is the parse tree to traverse.  OPTIONS is the plist holding
 DATA is the parse tree to traverse.  OPTIONS is the plist holding
@@ -3325,13 +3338,25 @@ paths."
 	  ;; Extract arguments from keyword's value.
 	  ;; Extract arguments from keyword's value.
 	  (let* ((value (org-element-property :value element))
 	  (let* ((value (org-element-property :value element))
 		 (ind (org-get-indentation))
 		 (ind (org-get-indentation))
+		 location
 		 (file (and (string-match
 		 (file (and (string-match
 			     "^\\(\".+?\"\\|\\S-+\\)\\(?:\\s-+\\|$\\)" value)
 			     "^\\(\".+?\"\\|\\S-+\\)\\(?:\\s-+\\|$\\)" value)
-			    (prog1 (expand-file-name
-				    (org-remove-double-quotes
-				     (match-string 1 value))
-				    dir)
+			    (prog1
+				(save-match-data
+				  (let ((matched (match-string 1 value)))
+				    (when (string-match "\\(::\\(.*?\\)\\)\"?\\'" matched)
+				      (setq location (match-string 2 matched))
+				      (setq matched
+					    (replace-match "" nil nil matched 1)))
+				    (expand-file-name
+				     (org-remove-double-quotes
+				      matched)
+				     dir)))
 			      (setq value (replace-match "" nil nil value)))))
 			      (setq value (replace-match "" nil nil value)))))
+		 (only-contents
+		  (and (string-match ":only-contents *\\([^: \r\t\n]\\S-*\\)?" value)
+		       (prog1 (org-not-nil (match-string 1 value))
+			 (setq value (replace-match "" nil nil value)))))
 		 (lines
 		 (lines
 		  (and (string-match
 		  (and (string-match
 			":lines +\"\\(\\(?:[0-9]+\\)?-\\(?:[0-9]+\\)?\\)\""
 			":lines +\"\\(\\(?:[0-9]+\\)?-\\(?:[0-9]+\\)?\\)\""
@@ -3391,17 +3416,88 @@ paths."
 	       (t
 	       (t
 		(insert
 		(insert
 		 (with-temp-buffer
 		 (with-temp-buffer
-		   (let ((org-inhibit-startup t)) (org-mode))
-		   (insert
-		    (org-export--prepare-file-contents
-		     file lines ind minlevel
-		     (or (gethash file file-prefix)
-			 (puthash file (incf current-prefix) file-prefix))))
+		   (let ((org-inhibit-startup t)
+			 (lines
+			  (if location
+			      (org-export--inclusion-absolute-lines
+			       file location only-contents lines)
+			    lines)))
+		     (org-mode)
+		     (insert
+		      (org-export--prepare-file-contents
+		       file lines ind minlevel
+		       (or (gethash file file-prefix)
+			   (puthash file (incf current-prefix) file-prefix)))))
 		   (org-export-expand-include-keyword
 		   (org-export-expand-include-keyword
 		    (cons (list file lines) included)
 		    (cons (list file lines) included)
 		    (file-name-directory file))
 		    (file-name-directory file))
 		   (buffer-string)))))))))))))
 		   (buffer-string)))))))))))))
 
 
+(defun org-export--inclusion-absolute-lines (file location only-contents lines)
+  "Resolve absolute lines for an included file with file-link.
+
+FILE is string file-name of the file to include.  LOCATION is a
+string name within FILE to be included (located via
+`org-link-search').  If ONLY-CONTENTS is non-nil only the
+contents of the named element will be included, as determined
+Org-Element.  If LINES is non-nil only those lines are included.
+
+Return a string of lines to be included in the format expected by
+`org-export--prepare-file-contents'."
+  (with-temp-buffer
+    (insert-file-contents file)
+    (unless (eq major-mode 'org-mode)
+      (let ((org-inhibit-startup t)) (org-mode)))
+    (condition-case err
+	;; Enforce consistent search.
+	(let ((org-link-search-must-match-exact-headline t))
+	  (org-link-search location))
+      (error
+       (error (format "%s for %s::%s" (error-message-string err) file location))))
+    (let* ((element (org-element-at-point))
+	   (contents-begin
+	    (and only-contents (org-element-property :contents-begin element))))
+      (narrow-to-region
+       (or contents-begin (org-element-property :begin element))
+       (org-element-property (if contents-begin :contents-end :end) element))
+      (when (and only-contents
+		 (memq (org-element-type element) '(headline inlinetask)))
+	;; Skip planning line and property-drawer.  If a normal drawer
+	;; precedes a property-drawer both will be included.
+	;; Remaining property-drawers are removed as needed in
+	;; `org-export--prepare-file-contents'.
+	(goto-char (point-min))
+	(when (org-looking-at-p org-planning-line-re) (forward-line))
+	(when (looking-at org-property-drawer-re) (goto-char (match-end 0)))
+	(unless (bolp) (forward-line))
+	(narrow-to-region (point) (point-max))))
+    (when lines
+      (org-skip-whitespace)
+      (beginning-of-line)
+      (let* ((lines (split-string lines "-"))
+	     (lbeg (string-to-number (car lines)))
+	     (lend (string-to-number (cadr lines)))
+	     (beg (if (zerop lbeg) (point-min)
+		    (goto-char (point-min))
+		    (forward-line (1- lbeg))
+		    (point)))
+	     (end (if (zerop lend) (point-max)
+		    (goto-char beg)
+		    (forward-line (1- lend))
+		    (point))))
+	(narrow-to-region beg end)))
+    (let ((end (point-max)))
+      (goto-char (point-min))
+      (widen)
+      (let ((start-line (line-number-at-pos)))
+	(format "%d-%d"
+		start-line
+		(save-excursion
+		  (+ start-line
+		     (let ((counter 0))
+		       (while (< (point) end) (incf counter) (forward-line))
+		       counter))))))))
+
 (defun org-export--prepare-file-contents (file &optional lines ind minlevel id)
 (defun org-export--prepare-file-contents (file &optional lines ind minlevel id)
   "Prepare the contents of FILE for inclusion and return them as a string.
   "Prepare the contents of FILE for inclusion and return them as a string.
 
 
@@ -3448,6 +3544,20 @@ with footnotes is included in a document."
     (skip-chars-backward " \r\t\n")
     (skip-chars-backward " \r\t\n")
     (forward-line)
     (forward-line)
     (delete-region (point) (point-max))
     (delete-region (point) (point-max))
+    ;; Remove property-drawers after drawers.
+    (when (or ind minlevel)
+      (unless (eq major-mode 'org-mode)
+	(let ((org-inhibit-startup t)) (org-mode)))
+      (goto-char (point-min))
+      (when (looking-at org-drawer-regexp)
+	(goto-char (match-end 0))
+	(search-forward-regexp org-drawer-regexp)
+	(forward-line 1)
+	(beginning-of-line))
+      (when (looking-at org-property-drawer-re)
+	(delete-region (match-beginning 0) (match-end 0))
+	(beginning-of-line))
+      (delete-region (point) (save-excursion (and (org-skip-whitespace) (point)))))
     ;; If IND is set, preserve indentation of include keyword until
     ;; If IND is set, preserve indentation of include keyword until
     ;; the first headline encountered.
     ;; the first headline encountered.
     (when ind
     (when ind
@@ -3776,7 +3886,12 @@ INFO is the plist used as a communication channel."
 ;;
 ;;
 ;; `org-export-get-headline-number' returns the section number of an
 ;; `org-export-get-headline-number' returns the section number of an
 ;; headline, while `org-export-number-to-roman' allows to convert it
 ;; headline, while `org-export-number-to-roman' allows to convert it
-;; to roman numbers.
+;; to roman numbers.  With an optional argument,
+;; `org-export-get-headline-number' returns a number to unnumbered
+;; headlines (used for internal id).
+;;
+;; `org-export-get-headline-id' returns the unique internal id of a
+;; headline.
 ;;
 ;;
 ;; `org-export-low-level-p', `org-export-first-sibling-p' and
 ;; `org-export-low-level-p', `org-export-first-sibling-p' and
 ;; `org-export-last-sibling-p' are three useful predicates when it
 ;; `org-export-last-sibling-p' are three useful predicates when it
@@ -3811,17 +3926,32 @@ and the last level being considered as high enough, or nil."
       (let ((level (org-export-get-relative-level headline info)))
       (let ((level (org-export-get-relative-level headline info)))
         (and (> level limit) (- level limit))))))
         (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."
+  (let ((numbered (org-export-numbered-headline-p headline info)))
+    (concat
+     (if numbered "sec-" "unnumbered-")
+     (mapconcat #'number-to-string
+		(if numbered
+		    (org-export-get-headline-number headline info)
+		  (cdr (assq headline (plist-get info :unnumbered-headline-id)))) "-"))))
+
 (defun org-export-get-headline-number (headline info)
 (defun org-export-get-headline-number (headline info)
-  "Return HEADLINE numbering as a list of numbers.
+  "Return numbered HEADLINE numbering as a list of numbers.
 INFO is a plist holding contextual information."
 INFO is a plist holding contextual information."
-  (cdr (assoc headline (plist-get info :headline-numbering))))
+  (and (org-export-numbered-headline-p headline info)
+       (cdr (assq headline (plist-get info :headline-numbering)))))
 
 
 (defun org-export-numbered-headline-p (headline info)
 (defun org-export-numbered-headline-p (headline info)
   "Return a non-nil value if HEADLINE element should be numbered.
   "Return a non-nil value if HEADLINE element should be numbered.
 INFO is a plist used as a communication channel."
 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-some
+	   (lambda (head) (org-not-nil (org-element-property :UNNUMBERED head)))
+	   (cons headline (org-export-get-genealogy headline)))
+    (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)
 (defun org-export-number-to-roman (n)
   "Convert integer N into a roman numeral."
   "Convert integer N into a roman numeral."

+ 25 - 0
testing/examples/include.org

@@ -8,3 +8,28 @@ Small Org file with an include keyword.
 
 
 * Heading
 * Heading
 body
 body
+
+* Another heading
+:PROPERTIES:
+:CUSTOM_ID: ah
+:END:
+1
+2
+3
+
+* A headline with a table
+:PROPERTIES:
+:CUSTOM_ID: ht
+:END:
+#+CAPTION: a table
+#+NAME: tbl
+| 1 |
+
+* drawer-headline
+:LOGBOOK:
+drawer
+:END:
+:PROPERTIES:
+:CUSTOM_ID: dh
+:END:
+content

+ 134 - 15
testing/lisp/test-ox.el

@@ -804,18 +804,18 @@ text
    (org-test-with-temp-text "#+INCLUDE: dummy.org"
    (org-test-with-temp-text "#+INCLUDE: dummy.org"
      (org-export-expand-include-keyword)))
      (org-export-expand-include-keyword)))
   ;; Full insertion with recursive inclusion.
   ;; Full insertion with recursive inclusion.
-  (org-test-with-temp-text
-      (format "#+INCLUDE: \"%s/examples/include.org\"" org-test-dir)
-    (org-export-expand-include-keyword)
-    (should (equal (buffer-string)
-		   "Small Org file with an include keyword.
-
-#+BEGIN_SRC emacs-lisp :exports results\n(+ 2 1)\n#+END_SRC
-
-Success!
-
-* Heading
-body\n")))
+  (should
+   (equal
+    (with-temp-buffer
+      (insert-file
+       (expand-file-name "examples/include.org" org-test-dir))
+      (replace-regexp-in-string
+       (regexp-quote "#+INCLUDE: \"include2.org\"")
+       "Success!" (buffer-string)))
+    (org-test-with-temp-text
+	(format "#+INCLUDE: \"%s/examples/include.org\"" org-test-dir)
+      (org-export-expand-include-keyword)
+      (buffer-string))))
   ;; Localized insertion.
   ;; Localized insertion.
   (org-test-with-temp-text
   (org-test-with-temp-text
       (format "#+INCLUDE: \"%s/examples/include.org\" :lines \"1-2\""
       (format "#+INCLUDE: \"%s/examples/include.org\" :lines \"1-2\""
@@ -829,7 +829,7 @@ body\n")))
     "* Top heading\n** Heading\nbody\n"
     "* Top heading\n** Heading\nbody\n"
     (org-test-with-temp-text
     (org-test-with-temp-text
 	(format
 	(format
-	 "* Top heading\n#+INCLUDE: \"%s/examples/include.org\" :lines \"9-\""
+	 "* Top heading\n#+INCLUDE: \"%s/examples/include.org\" :lines \"9-11\""
 	 org-test-dir)
 	 org-test-dir)
       (org-export-expand-include-keyword)
       (org-export-expand-include-keyword)
       (buffer-string))))
       (buffer-string))))
@@ -838,7 +838,7 @@ body\n")))
     "* Top heading\n* Heading\nbody\n"
     "* Top heading\n* Heading\nbody\n"
     (org-test-with-temp-text
     (org-test-with-temp-text
 	(format
 	(format
-	 "* Top heading\n#+INCLUDE: \"%s/examples/include.org\" :lines \"9-\" :minlevel 1"
+	 "* Top heading\n#+INCLUDE: \"%s/examples/include.org\" :lines \"9-11\" :minlevel 1"
 	 org-test-dir)
 	 org-test-dir)
       (org-export-expand-include-keyword)
       (org-export-expand-include-keyword)
       (buffer-string))))
       (buffer-string))))
@@ -918,7 +918,64 @@ Footnotes[fn:1], [fn:test] and [fn:inline:anonymous footnote].
 		(org-export-expand-include-keyword)
 		(org-export-expand-include-keyword)
 		(org-element-map (org-element-parse-buffer)
 		(org-element-map (org-element-parse-buffer)
 		    'footnote-reference
 		    'footnote-reference
-		  (lambda (ref) (org-element-property :label ref))))))))))))
+		  (lambda (ref) (org-element-property :label ref)))))))))))
+  ;; If only-contents is non-nil only include contents of element.
+  (should
+   (equal
+    "body\n"
+    (org-test-with-temp-text
+     (concat
+      (format "#+INCLUDE: \"%s/examples/include.org::*Heading\" " org-test-dir)
+      ":only-contents t")
+      (org-export-expand-include-keyword)
+      (buffer-string))))
+  ;; Headings can be included via CUSTOM_ID.
+  (should
+   (org-test-with-temp-text
+	(format "#+INCLUDE: \"%s/examples/include.org::#ah\"" org-test-dir)
+     (org-export-expand-include-keyword)
+     (goto-char (point-min))
+     (looking-at "* Another heading")))
+  ;; Named objects can be included.
+  (should
+   (equal
+    "| 1 |\n"
+    (org-test-with-temp-text
+	(format "#+INCLUDE: \"%s/examples/include.org::tbl\" :only-contents t" org-test-dir)
+      (org-export-expand-include-keyword)
+      (buffer-string))))
+  ;; Including non-existing elements should result in an error.
+  (should-error
+   (org-test-with-temp-text
+	(format "#+INCLUDE: \"%s/examples/include.org::*non-existing heading\"" org-test-dir)
+     (org-export-expand-include-keyword)))
+  ;; Lines work relatively to an included element.
+  (should
+   (equal
+    "2\n3\n"
+    (org-test-with-temp-text
+	(format "#+INCLUDE: \"%s/examples/include.org::#ah\" :only-contents t :lines \"2-3\"" org-test-dir)
+      (org-export-expand-include-keyword)
+      (buffer-string))))
+  ;; Properties should be dropped from headlines.
+  (should
+   (equal
+    (org-test-with-temp-text
+	(format "#+INCLUDE: \"%s/examples/include.org::#ht\" :only-contents t" org-test-dir)
+      (org-export-expand-include-keyword)
+      (buffer-string))
+    (org-test-with-temp-text
+	(format "#+INCLUDE: \"%s/examples/include.org::tbl\"" org-test-dir)
+      (org-export-expand-include-keyword)
+      (buffer-string))))
+  ;; Properties should be dropped, drawers should not be.
+  (should
+   (equal
+    ":LOGBOOK:\ndrawer\n:END:\ncontent\n"
+    (org-test-with-temp-text
+	(format "#+INCLUDE: \"%s/examples/include.org::#dh\" :only-contents t" org-test-dir)
+      (org-export-expand-include-keyword)
+      (buffer-string)))))
 
 
 (ert-deftest test-org-export/expand-macro ()
 (ert-deftest test-org-export/expand-macro ()
   "Test macro expansion in an Org buffer."
   "Test macro expansion in an Org buffer."
@@ -1576,6 +1633,68 @@ Paragraph[fn:1]"
        (lambda (h) (org-export-numbered-headline-p h info))
        (lambda (h) (org-export-numbered-headline-p h info))
        (plist-put info :section-numbers t)))))
        (plist-put info :section-numbers t)))))
 
 
+(ert-deftest test-org-export/org-export-get-headline-id ()
+  "Test `org-export-get-headline-id' specifications."
+  ;; Numbered headlines have IDs akin to "sec-N".
+  (should
+   (equal "sec-1"
+	  (org-test-with-parsed-data "* H"
+	    (org-export-get-headline-id
+	     (org-element-map tree 'headline #'identity info t)
+	     info))))
+  ;; The ID of numbered headlines reflect the hierarchy.
+  (should
+   (equal "sec-1-1"
+	  (org-test-with-parsed-data "* H1\n** H2"
+	    (org-export-get-headline-id
+	     (org-element-map tree 'headline
+	       (lambda (h)
+		 (and (equal "H2" (org-element-property :raw-value h)) h))
+	       info t)
+	     info))))
+  ;; Unnumbered headlines have IDs akin to "unnumbered-N".
+  (should
+   (equal "unnumbered-1"
+	  (org-test-with-parsed-data
+	      "* H\n:PROPERTIES:\n:UNNUMBERED: t\n:END:"
+	    (org-export-get-headline-id
+	     (org-element-map tree 'headline #'identity info t)
+	     info))))
+  ;; The ID of Unnumbered headlines do not reflect the hierarchy.
+  (should
+   (equal "unnumbered-2"
+	  (org-test-with-parsed-data
+	      "* H1\n:PROPERTIES:\n:UNNUMBERED: t\n:END:\n** H2"
+	    (org-export-get-headline-id
+	     (org-element-map tree 'headline
+	       (lambda (h)
+		 (and (equal "H2" (org-element-property :raw-value h)) h))
+	       info t)
+	     info))))
+  ;; When #+OPTIONS: num:nil all headlines are unnumbered.
+  (should
+   (equal "unnumbered-1"
+	  (org-test-with-parsed-data "* H\n#+OPTIONS: num:nil"
+	    (org-export-get-headline-id
+	     (org-element-map tree 'headline 'identity info t)
+	     info))))
+  ;; UNNUMBERED ignores inheritance.  Any non-nil value among
+  ;; ancestors disables numbering.
+  (should
+   (org-test-with-parsed-data
+       "* H
+:PROPERTIES:
+:UNNUMBERED: t
+:END:
+** H2
+:PROPERTIES:
+:UNNUMBERED: nil
+:END:
+*** H3"
+     (org-every
+      (lambda (h) (not (org-export-numbered-headline-p h info)))
+      (org-element-map tree 'headline #'identity info)))))
+
 (ert-deftest test-org-export/number-to-roman ()
 (ert-deftest test-org-export/number-to-roman ()
   "Test `org-export-number-to-roman' specifications."
   "Test `org-export-number-to-roman' specifications."
   ;; If number is negative, return it as a string.
   ;; If number is negative, return it as a string.