emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Ihor Radchenko <yantar92@posteo.net>
To: "Fraga, Eric" <e.fraga@ucl.ac.uk>
Cc: Emacs Org mode mailing list <emacs-orgmode@gnu.org>
Subject: Re: texinfo export has no targets for src blocks
Date: Mon, 23 Dec 2024 15:10:12 +0000	[thread overview]
Message-ID: <877c7ql9kb.fsf@localhost> (raw)
In-Reply-To: <87h676qr8n.fsf@ucl.ac.uk>

[-- Attachment #1: Type: text/plain, Size: 825 bytes --]

"Fraga, Eric" <e.fraga@ucl.ac.uk> writes:

> but also happen to have a code block
>
> #+name: model
> #+begin_src ...
>
> exporting to texinfo, asking to refer to [[model]], creates a reference
> to an non-existing target ("model") because (a) org appears to assume
> that you wish to reference the src block, not the headline, and (b) the
> src block (/@example/ in texinfo) is not labelled in the .texi output.
> See attached minimal example.
> ...

Thanks for reporting!
I tried to add support for #+name'd elements in ox-texinfo.
See the attached patch.

I simply prepended an @anchor to all paragraph level Org markup
elements. However, I am not 100% sure if it is always safe to do.
May you please test the patch on your side to make sure that things are
not going to be broken? (they are not on Org manual, at least)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-ox-texinfo-Support-references-to-name-d-elements.patch --]
[-- Type: text/x-patch, Size: 12835 bytes --]

From 3055cf517ba665f00820a179299df4cb43333c9b Mon Sep 17 00:00:00 2001
Message-ID: <3055cf517ba665f00820a179299df4cb43333c9b.1734966481.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Mon, 23 Dec 2024 16:06:07 +0100
Subject: [PATCH] ox-texinfo: Support references to #+name'd elements

* lisp/ox-texinfo.el (org-texinfo--prepend-anchor-maybe): New helper
function prepending an archor to named text.
(org-texinfo-center-block):
(org-texinfo-drawer):
(org-texinfo-dynamic-block):
(org-texinfo-example-block):
(org-texinfo-fixed-width):
(org-texinfo-latex-environment):
(org-texinfo-paragraph):
(org-texinfo-plain-list):
(org-texinfo-quote-block):
(org-texinfo-special-block):
(org-texinfo-src-block):
(org-texinfo-table):
(org-texinfo-verse-block): Use the new helper.
* testing/lisp/test-ox-texinfo.el (test-ox-texinfo/anchors): New test.

Reported-by: Fraga, Eric <e.fraga@ucl.ac.uk>
Link: https://orgmode.org/list/87h676qr8n.fsf@ucl.ac.uk
---
 lisp/ox-texinfo.el              | 124 ++++++++++++++++++++------------
 testing/lisp/test-ox-texinfo.el |  50 +++++++++++++
 2 files changed, 128 insertions(+), 46 deletions(-)

diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el
index cf7a96f78d..9e96d6c94f 100644
--- a/lisp/ox-texinfo.el
+++ b/lisp/ox-texinfo.el
@@ -553,6 +553,14 @@ (defun org-texinfo--get-node (datum info)
 	  (plist-put info :texinfo-node-cache (cons (cons datum name) cache))
 	  name))))
 
+(defun org-texinfo--prepend-anchor-maybe (contents node)
+  "Maybe prepend NODE anchor before CONTENTS.
+When NODE has :name property, prepend anchor named as :name value to
+CONTENTS.  Otherwise, return CONTENTS."
+  (if-let* ((label (org-element-property :name node)))
+      (concat "@anchor{" label "}\n" contents)
+    contents))
+
 (defun org-texinfo--sanitize-node (title)
   "Bend string TITLE to node line requirements.
 Trim string and collapse multiple whitespace characters as they
@@ -930,11 +938,13 @@ (defun org-texinfo-bold (_bold contents info)
 
 ;;;; Center Block
 
-(defun org-texinfo-center-block (_center-block contents _info)
+(defun org-texinfo-center-block (center-block contents _info)
   "Transcode a CENTER-BLOCK element from Org to Texinfo.
 CONTENTS holds the contents of the block.  INFO is a plist used
 as a communication channel."
-  (replace-regexp-in-string "\\(^\\).*?\\S-" "@center " contents nil nil 1))
+  (org-texinfo--prepend-anchor-maybe
+   (replace-regexp-in-string "\\(^\\).*?\\S-" "@center " contents nil nil 1)
+   center-block))
 
 ;;;; Clock
 
@@ -968,15 +978,15 @@ (defun org-texinfo-drawer (drawer contents info)
   (let* ((name (org-element-property :drawer-name drawer))
 	 (output (funcall (plist-get info :texinfo-format-drawer-function)
 			  name contents)))
-    output))
+    (org-texinfo--prepend-anchor-maybe output drawer)))
 
 ;;;; Dynamic Block
 
-(defun org-texinfo-dynamic-block (_dynamic-block contents _info)
+(defun org-texinfo-dynamic-block (dynamic-block contents _info)
   "Transcode a DYNAMIC-BLOCK element from Org to Texinfo.
 CONTENTS holds the contents of the block.  INFO is a plist
 holding contextual information."
-  contents)
+  (org-texinfo--prepend-anchor-maybe contents dynamic-block))
 
 ;;;; Entity
 
@@ -1028,9 +1038,11 @@ (defun org-texinfo-example-block (example-block _contents info)
   "Transcode an EXAMPLE-BLOCK element from Org to Texinfo.
 CONTENTS is nil.  INFO is a plist holding contextual
 information."
-  (format "@example\n%s@end example"
-	  (org-texinfo--sanitize-content
-	   (org-export-format-code-default example-block info))))
+  (org-texinfo--prepend-anchor-maybe
+   (format "@example\n%s@end example"
+	   (org-texinfo--sanitize-content
+	    (org-export-format-code-default example-block info)))
+   example-block))
 
 ;;; Export Block
 
@@ -1053,10 +1065,12 @@ ;;;; Fixed Width
 (defun org-texinfo-fixed-width (fixed-width _contents _info)
   "Transcode a FIXED-WIDTH element from Org to Texinfo.
 CONTENTS is nil.  INFO is a plist holding contextual information."
-  (format "@example\n%s\n@end example"
-	  (org-remove-indentation
-	   (org-texinfo--sanitize-content
-	    (org-element-property :value fixed-width)))))
+  (org-texinfo--prepend-anchor-maybe
+   (format "@example\n%s\n@end example"
+	   (org-remove-indentation
+	    (org-texinfo--sanitize-content
+	     (org-element-property :value fixed-width))))
+   fixed-width))
 
 ;;;; Footnote Reference
 
@@ -1274,11 +1288,13 @@ (defun org-texinfo-latex-environment (environment _contents info)
     (when (or (eq with-latex t)
               (and (eq with-latex 'detect)
                    (org-texinfo-supports-math-p)))
-      (let ((value (org-element-property :value environment)))
-        (string-join (list "@displaymath"
-                           (string-trim (org-remove-indentation value))
-                           "@end displaymath")
-                     "\n")))))
+      (org-texinfo--prepend-anchor-maybe
+       (let ((value (org-element-property :value environment)))
+         (string-join (list "@displaymath"
+                            (string-trim (org-remove-indentation value))
+                            "@end displaymath")
+                      "\n"))
+       environment))))
 
 ;;;; LaTeX Fragment
 
@@ -1534,7 +1550,7 @@ (defun org-texinfo-node-property (node-property _contents _info)
 
 ;;;; Paragraph
 
-(defun org-texinfo-paragraph (_paragraph contents _info)
+(defun org-texinfo-paragraph (paragraph contents _info)
   "Transcode a PARAGRAPH element from Org to Texinfo.
 CONTENTS is the contents of the paragraph, as a string.  INFO is
 the plist used as a communication channel."
@@ -1543,7 +1559,9 @@ (defun org-texinfo-paragraph (_paragraph contents _info)
   ;; Multiple newlines may appear in CONTENTS, for example, when
   ;; certain objects are stripped from export, leaving single newlines
   ;; before and after.
-  (org-remove-blank-lines contents))
+  (org-texinfo--prepend-anchor-maybe
+   (org-remove-blank-lines contents)
+   paragraph))
 
 ;;;; Plain List
 
@@ -1571,12 +1589,14 @@ (defun org-texinfo-plain-list (plain-list contents info)
 		     ((eq type 'unordered) "itemize")
 		     ((member table-type '("ftable" "vtable")) table-type)
 		     (t "table"))))
-    (format "@%s\n%s@end %s"
-	    (cond ((eq type 'descriptive) (concat list-type " " indic))
-		  (enum (format "%s %s" list-type enum))
-		  (t list-type))
-	    contents
-	    list-type)))
+    (org-texinfo--prepend-anchor-maybe
+     (format "@%s\n%s@end %s"
+	     (cond ((eq type 'descriptive) (concat list-type " " indic))
+		   (enum (format "%s %s" list-type enum))
+		   (t list-type))
+	     contents
+	     list-type)
+     plain-list)))
 
 ;;;; Plain Text
 
@@ -1662,10 +1682,12 @@ (defun org-texinfo-quote-block (quote-block contents _info)
 holding contextual information."
   (let ((tag (org-export-read-attribute :attr_texinfo quote-block :tag))
 	(author (org-export-read-attribute :attr_texinfo quote-block :author)))
-    (format "@quotation%s\n%s%s\n@end quotation"
-	    (if tag (concat " " tag) "")
-	    contents
-	    (if author (concat "\n@author " author) ""))))
+    (org-texinfo--prepend-anchor-maybe
+     (format "@quotation%s\n%s%s\n@end quotation"
+	     (if tag (concat " " tag) "")
+	     contents
+	     (if author (concat "\n@author " author) ""))
+     quote-block)))
 
 ;;;; Radio Target
 
@@ -1702,11 +1724,13 @@ (defun org-texinfo-special-block (special-block contents _info)
               (org-element-property :ox-texinfo--options special-block)
               (org-export-read-attribute :attr_texinfo special-block :options)))
 	(type (org-element-property :type special-block)))
-    (format "@%s%s\n%s@end %s"
-	    type
-	    (if opt (concat " " opt) "")
-	    (or contents "")
-	    type)))
+    (org-texinfo--prepend-anchor-maybe
+     (format "@%s%s\n%s@end %s"
+	     type
+	     (if opt (concat " " opt) "")
+	     (or contents "")
+	     type)
+     special-block)))
 
 ;;;; Src Block
 
@@ -1724,13 +1748,15 @@ (defun org-texinfo-src-block (src-block _contents info)
 		 code))
 	 (caption (org-export-get-caption src-block))
 	 (shortcaption (org-export-get-caption src-block t)))
-    (if (not (or caption shortcaption)) value
+    (cond
+     ((or caption shortcaption)
       (org-texinfo--wrap-float value
 			       info
 			       (org-export-translate "Listing" :utf-8 info)
-			       (org-texinfo--get-node src-block info)
+                               (org-element-property :name src-block)
 			       caption
-			       shortcaption))))
+			       shortcaption))
+     (t (org-texinfo--prepend-anchor-maybe value src-block)))))
 
 ;;;; Statistics Cookie
 
@@ -1771,9 +1797,11 @@ (defun org-texinfo-table (table contents info)
 CONTENTS is the contents of the table.  INFO is a plist holding
 contextual information."
   (if (eq (org-element-property :type table) 'table.el)
-      (format "@verbatim\n%s@end verbatim"
-	      (org-element-normalize-string
-	       (org-element-property :value table)))
+      (org-texinfo--prepend-anchor-maybe
+       (format "@verbatim\n%s@end verbatim"
+	       (org-element-normalize-string
+	        (org-element-property :value table)))
+       table)
     (let* ((col-width (org-export-read-attribute :attr_texinfo table :columns))
 	   (columns
 	    (if col-width (format "@columnfractions %s" col-width)
@@ -1783,13 +1811,15 @@ (defun org-texinfo-table (table contents info)
 	   (table-str (format "@multitable %s\n%s@end multitable"
 			      columns
 			      contents)))
-      (if (not (or caption shortcaption)) table-str
-	(org-texinfo--wrap-float table-str
+      (cond
+       ((or caption shortcaption)
+        (org-texinfo--wrap-float table-str
 				 info
 				 (org-export-translate "Table" :utf-8 info)
-				 (org-texinfo--get-node table info)
+                                 (org-element-property :name table)
 				 caption
-				 shortcaption)))))
+				 shortcaption))
+       (t (org-texinfo--prepend-anchor-maybe table-str table))))))
 
 (defun org-texinfo-table-column-widths (table info)
   "Determine the largest table cell in each column to process alignment.
@@ -1891,11 +1921,13 @@ (defun org-texinfo-verbatim (verbatim _contents info)
 
 ;;;; Verse Block
 
-(defun org-texinfo-verse-block (_verse-block contents _info)
+(defun org-texinfo-verse-block (verse-block contents _info)
   "Transcode a VERSE-BLOCK element from Org to Texinfo.
 CONTENTS is verse block contents.  INFO is a plist holding
 contextual information."
-  (format "@display\n%s@end display" contents))
+  (org-texinfo--prepend-anchor-maybe
+   (format "@display\n%s@end display" contents)
+   verse-block))
 
 \f
 ;;; Public Functions
diff --git a/testing/lisp/test-ox-texinfo.el b/testing/lisp/test-ox-texinfo.el
index 681af7363e..6b6d16aea7 100644
--- a/testing/lisp/test-ox-texinfo.el
+++ b/testing/lisp/test-ox-texinfo.el
@@ -374,6 +374,56 @@ (ert-deftest test-ox-texinfo/references ()
           (re-search-forward "@ref{B, , B}")
           (re-search-forward "@ref{B, , C}")))))))
 
+(ert-deftest test-ox-texinfo/anchors ()
+  "Test anchors and references."
+  (should
+   (org-test-with-temp-text
+       (string-join
+        (list "* The document"
+              "** The model"
+              "This is some text describing the model."
+              "#+name: model"
+              "#+begin_src julia"
+              "  struct Model"
+              "  end"
+              "#+end_src"
+              "** Solution"
+              "Solving the model ([[model]]) leads to some interesting results."
+              )
+        "\n")
+     (let ((export-buffer "*Test Texinfo Export*")
+           (org-export-show-temporary-export-buffer nil))
+       (org-export-to-buffer 'texinfo export-buffer
+         nil nil nil nil nil
+         #'texinfo-mode)
+       (with-current-buffer export-buffer
+         (goto-char (point-min))
+         (and
+          (re-search-forward "@anchor{model}")
+          (re-search-forward "@ref{model}"))))))
+  (should
+   (org-test-with-temp-text
+       (string-join
+        (list "* The document"
+              "** The model"
+              "This is some text describing the model."
+              "#+name: model"
+              "| foo | bar |"
+              "** Solution"
+              "Solving the model ([[model]]) leads to some interesting results."
+              )
+        "\n")
+     (let ((export-buffer "*Test Texinfo Export*")
+           (org-export-show-temporary-export-buffer nil))
+       (org-export-to-buffer 'texinfo export-buffer
+         nil nil nil nil nil
+         #'texinfo-mode)
+       (with-current-buffer export-buffer
+         (goto-char (point-min))
+         (and
+          (re-search-forward "@anchor{model}")
+          (re-search-forward "@ref{model}")))))))
+
 \f
 ;;; Headings with links
 
-- 
2.47.1


[-- Attachment #3: Type: text/plain, Size: 223 bytes --]


-- 
Ihor Radchenko // yantar92,
Org mode maintainer,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>

  reply	other threads:[~2024-12-23 15:09 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-12-14 14:22 texinfo export has no targets for src blocks Fraga, Eric
2024-12-23 15:10 ` Ihor Radchenko [this message]
2024-12-23 15:25   ` Fraga, Eric
2024-12-23 16:20     ` Ihor Radchenko

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=877c7ql9kb.fsf@localhost \
    --to=yantar92@posteo.net \
    --cc=e.fraga@ucl.ac.uk \
    --cc=emacs-orgmode@gnu.org \
    /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).