diff options
Diffstat (limited to 'lisp/org/ox-texinfo.el')
-rw-r--r-- | lisp/org/ox-texinfo.el | 949 |
1 files changed, 525 insertions, 424 deletions
diff --git a/lisp/org/ox-texinfo.el b/lisp/org/ox-texinfo.el index 31d91ebfb80..35927d99533 100644 --- a/lisp/org/ox-texinfo.el +++ b/lisp/org/ox-texinfo.el @@ -1,4 +1,4 @@ -;;; ox-texinfo.el --- Texinfo Back-End for Org Export Engine +;;; ox-texinfo.el --- Texinfo Back-End for Org Export Engine -*- lexical-binding: t; -*- ;; Copyright (C) 2012-2017 Free Software Foundation, Inc. ;; Author: Jonathan Leech-Pepin <jonathan.leechpepin at gmail dot com> @@ -25,7 +25,7 @@ ;;; Code: -(eval-when-compile (require 'cl)) +(require 'cl-lib) (require 'ox) (defvar orgtbl-exp-regexp) @@ -39,8 +39,6 @@ (center-block . org-texinfo-center-block) (clock . org-texinfo-clock) (code . org-texinfo-code) - (comment . (lambda (&rest args) "")) - (comment-block . (lambda (&rest args) "")) (drawer . org-texinfo-drawer) (dynamic-block . org-texinfo-dynamic-block) (entity . org-texinfo-entity) @@ -58,18 +56,19 @@ (keyword . org-texinfo-keyword) (line-break . org-texinfo-line-break) (link . org-texinfo-link) + (node-property . org-texinfo-node-property) (paragraph . org-texinfo-paragraph) (plain-list . org-texinfo-plain-list) (plain-text . org-texinfo-plain-text) (planning . org-texinfo-planning) (property-drawer . org-texinfo-property-drawer) (quote-block . org-texinfo-quote-block) - (quote-section . org-texinfo-quote-section) (radio-target . org-texinfo-radio-target) (section . org-texinfo-section) (special-block . org-texinfo-special-block) (src-block . org-texinfo-src-block) (statistics-cookie . org-texinfo-statistics-cookie) + (strike-through . org-texinfo-strike-through) (subscript . org-texinfo-subscript) (superscript . org-texinfo-superscript) (table . org-texinfo-table) @@ -78,28 +77,46 @@ (target . org-texinfo-target) (template . org-texinfo-template) (timestamp . org-texinfo-timestamp) + (underline . org-texinfo-underline) (verbatim . org-texinfo-verbatim) (verse-block . org-texinfo-verse-block)) - :export-block "TEXINFO" :filters-alist - '((:filter-headline . org-texinfo-filter-section-blank-lines) + '((:filter-headline . org-texinfo--filter-section-blank-lines) (:filter-parse-tree . org-texinfo--normalize-headlines) - (:filter-section . org-texinfo-filter-section-blank-lines)) + (:filter-section . org-texinfo--filter-section-blank-lines)) :menu-entry '(?i "Export to Texinfo" ((?t "As TEXI file" org-texinfo-export-to-texinfo) - (?i "As INFO file" org-texinfo-export-to-info))) + (?i "As INFO file" org-texinfo-export-to-info) + (?o "As INFO file and open" + (lambda (a s v b) + (if a (org-texinfo-export-to-info t s v b) + (org-open-file (org-texinfo-export-to-info nil s v b))))))) :options-alist '((:texinfo-filename "TEXINFO_FILENAME" nil nil t) (:texinfo-class "TEXINFO_CLASS" nil org-texinfo-default-class t) (:texinfo-header "TEXINFO_HEADER" nil nil newline) (:texinfo-post-header "TEXINFO_POST_HEADER" nil nil newline) - (:subtitle "SUBTITLE" nil nil newline) + (:subtitle "SUBTITLE" nil nil parse) (:subauthor "SUBAUTHOR" nil nil newline) (:texinfo-dircat "TEXINFO_DIR_CATEGORY" nil nil t) (:texinfo-dirtitle "TEXINFO_DIR_TITLE" nil nil t) (:texinfo-dirdesc "TEXINFO_DIR_DESC" nil nil t) - (:texinfo-printed-title "TEXINFO_PRINTED_TITLE" nil nil t))) + (:texinfo-printed-title "TEXINFO_PRINTED_TITLE" nil nil t) + ;; Other variables. + (:texinfo-classes nil nil org-texinfo-classes) + (:texinfo-format-headline-function nil nil org-texinfo-format-headline-function) + (:texinfo-node-description-column nil nil org-texinfo-node-description-column) + (:texinfo-active-timestamp-format nil nil org-texinfo-active-timestamp-format) + (:texinfo-inactive-timestamp-format nil nil org-texinfo-inactive-timestamp-format) + (:texinfo-diary-timestamp-format nil nil org-texinfo-diary-timestamp-format) + (:texinfo-link-with-unknown-path-format nil nil org-texinfo-link-with-unknown-path-format) + (:texinfo-tables-verbatim nil nil org-texinfo-tables-verbatim) + (:texinfo-table-scientific-notation nil nil org-texinfo-table-scientific-notation) + (:texinfo-def-table-markup nil nil org-texinfo-def-table-markup) + (:texinfo-text-markup-alist nil nil org-texinfo-text-markup-alist) + (:texinfo-format-drawer-function nil nil org-texinfo-format-drawer-function) + (:texinfo-format-inlinetask-function nil nil org-texinfo-format-inlinetask-function))) @@ -193,7 +210,8 @@ a format string in which the section title will be added." ;;;; Headline -(defcustom org-texinfo-format-headline-function 'ignore +(defcustom org-texinfo-format-headline-function + 'org-texinfo-format-headline-default-function "Function to format headline text. This function will be called with 5 arguments: @@ -203,23 +221,11 @@ PRIORITY the priority of the headline (integer or nil) TEXT the main headline text (string). TAGS the tags as a list of strings (list of strings or nil). -The function result will be used in the section format string. - -As an example, one could set the variable to the following, in -order to reproduce the default set-up: - -\(defun org-texinfo-format-headline (todo todo-type priority text tags) - \"Default format function for a headline.\" - (concat (when todo - (format \"\\\\textbf{\\\\textsc{\\\\textsf{%s}}} \" todo)) - (when priority - (format \"\\\\framebox{\\\\#%c} \" priority)) - text - (when tags - (format \"\\\\hfill{}\\\\textsc{%s}\" - (mapconcat \\='identity tags \":\"))))" +The function result will be used in the section format string." :group 'org-export-texinfo - :type 'function) + :type 'function + :version "26.1" + :package-version '(Org . "8.3")) ;;;; Node listing (menu) @@ -263,6 +269,7 @@ be placed after the end of the title." (defcustom org-texinfo-table-scientific-notation "%s\\,(%s)" "Format string to display numbers in scientific notation. + The format should have \"%s\" twice, for mantissa and exponent \(i.e. \"%s\\\\times10^{%s}\"). @@ -273,7 +280,12 @@ When nil, no transformation is made." (const :tag "No formatting" nil))) (defcustom org-texinfo-def-table-markup "@samp" - "Default setting for @table environments." + "Default markup for first column in two-column tables. + +This should an indicating command, e.g., \"@code\", \"@kbd\" or +\"@asis\". + +It can be overridden locally using the \":indic\" attribute." :group 'org-export-texinfo :type 'string) @@ -282,29 +294,28 @@ When nil, no transformation is made." (defcustom org-texinfo-text-markup-alist '((bold . "@strong{%s}") (code . code) (italic . "@emph{%s}") - (verbatim . verb) - (comment . "@c %s")) + (verbatim . verb)) "Alist of Texinfo expressions to convert text markup. -The key must be a symbol among `bold', `italic' and `comment'. -The value is a formatting string to wrap fontified text with. +The key must be a symbol among `bold', `code', `italic', +`strike-through', `underscore' and `verbatim'. The value is +a formatting string to wrap fontified text with. Value can also be set to the following symbols: `verb' and -`code'. For the former, Org will use \"@verb\" to -create a format string and select a delimiter character that -isn't in the string. For the latter, Org will use \"@code\" -to typeset and try to protect special characters. +`code'. For the former, Org will use \"@verb\" to create +a format string and select a delimiter character that isn't in +the string. For the latter, Org will use \"@code\" to typeset +and try to protect special characters. If no association can be found for a given markup, text will be returned as-is." :group 'org-export-texinfo :type 'alist - :options '(bold code italic verbatim comment)) + :options '(bold code italic strike-through underscore verbatim)) ;;;; Drawers -(defcustom org-texinfo-format-drawer-function - (lambda (name contents) contents) +(defcustom org-texinfo-format-drawer-function (lambda (_name contents) contents) "Function called to format a drawer in Texinfo code. The function must accept two parameters: @@ -321,7 +332,8 @@ The default function simply returns the value of CONTENTS." ;;;; Inlinetasks -(defcustom org-texinfo-format-inlinetask-function 'ignore +(defcustom org-texinfo-format-inlinetask-function + 'org-texinfo-format-inlinetask-default-function "Function called to format an inlinetask in Texinfo code. The function must accept six parameters: @@ -332,26 +344,7 @@ The function must accept six parameters: TAGS the inlinetask tags, as a list of strings. CONTENTS the contents of the inlinetask, as a string. -The function should return the string to be exported. - -For example, the variable could be set to the following function -in order to mimic default behavior: - -\(defun org-texinfo-format-inlinetask (todo type priority name tags contents) -\"Format an inline task element for Texinfo export.\" - (let ((full-title - (concat - (when todo - (format \"@strong{%s} \" todo)) - (when priority (format \"#%c \" priority)) - title - (when tags - (format \":%s:\" - (mapconcat \\='identity tags \":\"))))) - (format (concat \"@center %s\n\n\" - \"%s\" - \"\n\")) - full-title contents))" +The function should return the string to be exported." :group 'org-export-texinfo :type 'function) @@ -359,10 +352,13 @@ in order to mimic default behavior: (defcustom org-texinfo-info-process '("makeinfo %f") "Commands to process a Texinfo file to an INFO file. -This is list of strings, each of them will be given to the shell -as a command. %f in the command will be replaced by the full -file name, %b by the file base name (i.e without extension) and -%o by the base directory of the file." + +This is a list of strings, each of them will be given to the +shell as a command. %f in the command will be replaced by the +relative file name, %F by the absolute file name, %b by the file +base name (i.e. without directory and extension parts), %o by the +base directory of the file and %O by the absolute file name of +the output file." :group 'org-export-texinfo :type '(repeat :tag "Shell command sequence" (string :tag "Shell command"))) @@ -398,15 +394,19 @@ Specified coding system will be matched against these strings. If two strings share the same prefix (e.g. \"ISO-8859-1\" and \"ISO-8859-15\"), the most specific one has to be listed first.") +(defconst org-texinfo-inline-image-rules + (list (cons "file" + (regexp-opt '("eps" "pdf" "png" "jpg" "jpeg" "gif" "svg")))) + "Rules characterizing image files that can be inlined.") + ;;; Internal Functions -(defun org-texinfo-filter-section-blank-lines (headline back-end info) +(defun org-texinfo--filter-section-blank-lines (headline _backend _info) "Filter controlling number of blank lines after a section." - (let ((blanks (make-string 2 ?\n))) - (replace-regexp-in-string "\n\\(?:\n[ \t]*\\)*\\'" blanks headline))) + (replace-regexp-in-string "\n\\(?:\n[ \t]*\\)*\\'" "\n\n" headline)) -(defun org-texinfo--normalize-headlines (tree back-end info) +(defun org-texinfo--normalize-headlines (tree _backend info) "Normalize headlines in TREE. BACK-END is the symbol specifying back-end used for export. INFO @@ -435,76 +435,116 @@ Return new tree." "Return a character not used in string S. This is used to choose a separator for constructs like \\verb." (let ((ll "~,./?;':\"|!@#%^&-_=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<>()[]{}")) - (loop for c across ll - when (not (string-match (regexp-quote (char-to-string c)) s)) - return (char-to-string c)))) + (cl-loop for c across ll + when (not (string-match (regexp-quote (char-to-string c)) s)) + return (char-to-string c)))) -(defun org-texinfo--text-markup (text markup) +(defun org-texinfo--text-markup (text markup _info) "Format TEXT depending on MARKUP text markup. -See `org-texinfo-text-markup-alist' for details." - (let ((fmt (cdr (assq markup org-texinfo-text-markup-alist)))) - (cond - ;; No format string: Return raw text. - ((not fmt) text) - ((eq 'verb fmt) - (let ((separator (org-texinfo--find-verb-separator text))) - (concat "@verb{" separator text separator "}"))) - ((eq 'code fmt) - (let ((start 0) - (rtn "") - char) - (while (string-match "[@{}]" text) - (setq char (match-string 0 text)) - (if (> (match-beginning 0) 0) - (setq rtn (concat rtn (substring text 0 (match-beginning 0))))) - (setq text (substring text (1+ (match-beginning 0)))) - (setq char (concat "@" char) - rtn (concat rtn char))) - (setq text (concat rtn text) - fmt "@code{%s}") - (format fmt text))) - ;; Else use format string. - (t (format fmt text))))) - -(defun org-texinfo--get-node (blob info) - "Return node or anchor associated to BLOB. -BLOB is an element or object. INFO is a plist used as +INFO is a plist used as a communication channel. See +`org-texinfo-text-markup-alist' for details." + (pcase (cdr (assq markup org-texinfo-text-markup-alist)) + ;; No format string: Return raw text. + (`nil text) + (`verb + (let ((separator (org-texinfo--find-verb-separator text))) + (concat "@verb{" separator text separator "}"))) + (`code + (format "@code{%s}" (replace-regexp-in-string "[@{}]" "@\\&" text))) + ;; Else use format string. + (fmt (format fmt text)))) + +(defun org-texinfo--get-node (datum info) + "Return node or anchor associated to DATUM. +DATUM is an element or object. INFO is a plist used as a communication channel. The function guarantees the node or anchor name is unique." (let ((cache (plist-get info :texinfo-node-cache))) - (or (cdr (assq blob cache)) - (let ((name - (org-texinfo--sanitize-node - (case (org-element-type blob) - (headline - (org-export-data (org-export-get-alt-title blob info) info)) - ((radio-target target) (org-element-property :value blob)) - (otherwise (or (org-element-property :name blob) "")))))) - ;; Ensure NAME is unique. - (while (rassoc name cache) (setq name (concat name "x"))) - (plist-put info :texinfo-node-cache (cons (cons blob name) cache)) + (or (cdr (assq datum cache)) + (let* ((salt 0) + (basename + (org-texinfo--sanitize-node + (if (eq (org-element-type datum) 'headline) + (org-texinfo--sanitize-title + (org-export-get-alt-title datum info) info) + (org-export-get-reference datum info)))) + (name basename)) + ;; Ensure NAME is unique and not reserved node name "Top". + (while (or (equal name "Top") (rassoc name cache)) + (setq name (concat basename (format " %d" (cl-incf salt))))) + (plist-put info :texinfo-node-cache (cons (cons datum name) cache)) name)))) -;;;; Menu sanitizing - (defun org-texinfo--sanitize-node (title) "Bend string TITLE to node line requirements. Trim string and collapse multiple whitespace characters as they -are not significant. Also remove the following characters: @ -{ } ( ) : . ," - (replace-regexp-in-string - "[:,.]" "" +are not significant. Replace leading left parenthesis, when +followed by a right parenthesis, with a square bracket. Remove +periods, commas and colons." + (org-trim (replace-regexp-in-string - "\\`(\\(.*)\\)" "[\\1" - (org-trim (replace-regexp-in-string "[ \t]\\{2,\\}" " " title))))) - -;;;; Content sanitizing + "[ \t]+" " " + (replace-regexp-in-string + "[:,.]" "" + (replace-regexp-in-string "\\`(\\(.*?)\\)" "[\\1" title))))) + +(defun org-texinfo--sanitize-title (title info) + "Make TITLE suitable as a section name. +TITLE is a string or a secondary string. INFO is the current +export state, as a plist." + (org-export-data-with-backend + title + (org-export-create-backend + :parent 'texinfo + :transcoders '((footnote-reference . ignore) + (link . (lambda (object c i) c)) + (radio-target . (lambda (object c i) c)) + (target . ignore))) + info)) (defun org-texinfo--sanitize-content (text) "Escape special characters in string TEXT. Special characters are: @ { }" (replace-regexp-in-string "[@{}]" "@\\&" text)) +(defun org-texinfo--wrap-float (value info &optional type label caption short) + "Wrap string VALUE within a @float command. +INFO is the current export state, as a plist. TYPE is float +type, as a string. LABEL is the cross reference label for the +float, as a string. CAPTION and SHORT are, respectively, the +caption and shortcaption used for the float, as secondary +strings (e.g., returned by `org-export-get-caption')." + (let* ((backend + (org-export-create-backend + :parent 'texinfo + :transcoders '((link . (lambda (object c i) c)) + (radio-target . (lambda (object c i) c)) + (target . ignore)))) + (short-backend + (org-export-create-backend + :parent 'texinfo + :transcoders '((footnote-reference . ignore) + (inline-src-block . ignore) + (link . (lambda (object c i) c)) + (radio-target . (lambda (object c i) c)) + (target . ignore) + (verbatim . ignore)))) + (short-str + (if (and short caption) + (format "@shortcaption{%s}\n" + (org-export-data-with-backend short short-backend info)) + "")) + (caption-str + (if (or short caption) + (format "@caption{%s}\n" + (org-export-data-with-backend + (or caption short) + (if (equal short-str "") short-backend backend) + info)) + ""))) + (format "@float %s%s\n%s\n%s%s@end float" + type (if label (concat "," label) "") value caption-str short-str))) + ;;; Template (defun org-texinfo-template (contents info) @@ -537,7 +577,7 @@ holding export options." (name (symbol-name (or org-texinfo-coding-system buffer-file-coding-system)))) (dolist (system org-texinfo-supported-coding-systems "UTF-8") - (when (org-string-match-p (regexp-quote system) name) + (when (string-match-p (regexp-quote system) name) (throw 'coding-system system)))))) (language (plist-get info :language)) (case-fold-search nil)) @@ -574,7 +614,7 @@ holding export options." (let ((dirdesc (let ((desc (plist-get info :texinfo-dirdesc))) (cond ((not desc) nil) - ((org-string-match-p "\\.$" desc) desc) + ((string-suffix-p "." desc) desc) (t (concat desc ".")))))) (if dirdesc (format "%-23s %s" dirtitle dirdesc) dirtitle)) "\n" @@ -582,11 +622,14 @@ holding export options." ;; Title "@finalout\n" "@titlepage\n" - (format "@title %s\n" (or (plist-get info :texinfo-printed-title) title)) - (let ((subtitle (plist-get info :subtitle))) - (and subtitle - (org-element-normalize-string - (replace-regexp-in-string "^" "@subtitle " subtitle)))) + (when (plist-get info :with-title) + (concat + (format "@title %s\n" + (or (plist-get info :texinfo-printed-title) title "")) + (let ((subtitle (plist-get info :subtitle))) + (when subtitle + (format "@subtitle %s\n" + (org-export-data subtitle info)))))) (when (plist-get info :with-author) (concat ;; Primary author. @@ -608,11 +651,17 @@ holding export options." "@end titlepage\n\n" ;; Table of contents. (and (plist-get info :with-toc) "@contents\n\n") - ;; Configure Top Node when not for Tex + ;; Configure Top Node when not for TeX. Also include contents + ;; from the first section of the document. "@ifnottex\n" "@node Top\n" (format "@top %s\n" title) - (and copying "@insertcopying\n") + (let* ((first-section + (org-element-map (plist-get info :parse-tree) 'section + #'identity info t '(headline))) + (top-contents + (org-export-data (org-element-contents first-section) info))) + (and (org-string-nw-p top-contents) (concat "\n" top-contents))) "@end ifnottex\n\n" ;; Menu. (org-texinfo-make-menu (plist-get info :parse-tree) info 'master) @@ -620,10 +669,8 @@ holding export options." ;; Document's body. contents "\n" ;; Creator. - (case (plist-get info :with-creator) - ((nil) nil) - (comment (format "@c %s\n" (plist-get info :creator))) - (otherwise (concat (plist-get info :creator) "\n"))) + (and (plist-get info :with-creator) + (concat (plist-get info :creator) "\n")) ;; Document end. "@bye"))) @@ -633,15 +680,15 @@ holding export options." ;;;; Bold -(defun org-texinfo-bold (bold contents info) +(defun org-texinfo-bold (_bold contents info) "Transcode BOLD from Org to Texinfo. CONTENTS is the text with bold markup. INFO is a plist holding contextual information." - (org-texinfo--text-markup contents 'bold)) + (org-texinfo--text-markup contents 'bold 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." @@ -649,28 +696,26 @@ as a communication channel." ;;;; Clock -(defun org-texinfo-clock (clock contents info) +(defun org-texinfo-clock (clock _contents info) "Transcode a CLOCK element from Org to Texinfo. CONTENTS is nil. INFO is a plist holding contextual information." (concat "@noindent" (format "@strong{%s} " org-clock-string) - (format org-texinfo-inactive-timestamp-format - (concat (org-translate-time - (org-element-property :raw-value - (org-element-property :value clock))) + (format (plist-get info :texinfo-inactive-timestamp-format) + (concat (org-timestamp-translate (org-element-property :value clock)) (let ((time (org-element-property :duration clock))) (and time (format " (%s)" time))))) "@*")) ;;;; Code -(defun org-texinfo-code (code contents info) +(defun org-texinfo-code (code _contents info) "Transcode a CODE object from Org to Texinfo. CONTENTS is nil. INFO is a plist used as a communication channel." - (org-texinfo--text-markup (org-element-property :value code) 'code)) + (org-texinfo--text-markup (org-element-property :value code) 'code info)) ;;;; Drawer @@ -679,13 +724,13 @@ channel." CONTENTS holds the contents of the block. INFO is a plist holding contextual information." (let* ((name (org-element-property :drawer-name drawer)) - (output (funcall org-texinfo-format-drawer-function + (output (funcall (plist-get info :texinfo-format-drawer-function) name contents))) output)) ;;;; 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." @@ -693,33 +738,68 @@ holding contextual information." ;;;; Entity -(defun org-texinfo-entity (entity contents info) - "Transcode an ENTITY object from Org to Texinfo. -CONTENTS are the definition itself. INFO is a plist holding -contextual information." - (let ((ent (org-element-property :latex entity))) - (if (org-element-property :latex-math-p entity) (format "@math{%s}" ent) ent))) +(defun org-texinfo-entity (entity _contents _info) + "Transcode an ENTITY object from Org to Texinfo." + ;; Since there is not specific Texinfo entry in entities, use + ;; Texinfo-specific commands whenever possible, and fallback to + ;; UTF-8 otherwise. + (pcase (org-element-property :name entity) + ("AElig" "@AE{}") + ("aelig" "@ae{}") + ((or "bull" "bullet") "@bullet{}") + ("copy" "@copyright{}") + ("deg" "@textdegree{}") + ((or "dots" "hellip") "@dots{}") + ("equiv" "@equiv{}") + ((or "euro" "EUR") "@euro{}") + ((or "ge" "geq") "@geq{}") + ("laquo" "@guillemetleft{}") + ("iexcl" "@exclamdown{}") + ("imath" "@dotless{i}") + ("iquest" "@questiondown{}") + ("jmath" "@dotless{j}") + ((or "le" "leq") "@leq{}") + ("lsaquo" "@guilsinglleft{}") + ("mdash" "---") + ("minus" "@minus{}") + ("nbsp" "@tie{}") + ("ndash" "--") + ("OElig" "@OE{}") + ("oelig" "@oe{}") + ("ordf" "@ordf{}") + ("ordm" "@ordm{}") + ("pound" "@pound{}") + ("raquo" "@guillemetright{}") + ((or "rArr" "Rightarrow") "@result{}") + ("reg" "@registeredsymbol{}") + ((or "rightarrow" "to" "rarr") "@arrow{}") + ("rsaquo" "@guilsinglright{}") + ("thorn" "@th{}") + ("THORN" "@TH{}") + ((and (pred (string-prefix-p "_")) name) ;spacing entities + (format "@w{%s}" (substring name 1))) + (_ (org-element-property :utf-8 entity)))) ;;;; Example Block -(defun org-texinfo-example-block (example-block contents info) +(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 "@verbatim\n%s@end verbatim" (org-export-format-code-default example-block info))) -;;;; Export Block +;;; Export Block -(defun org-texinfo-export-block (export-block contents info) +(defun org-texinfo-export-block (export-block _contents _info) "Transcode a EXPORT-BLOCK element from Org to Texinfo. CONTENTS is nil. INFO is a plist holding contextual information." (when (string= (org-element-property :type export-block) "TEXINFO") (org-remove-indentation (org-element-property :value export-block)))) -;;;; Export Snippet +;;; Export Snippet -(defun org-texinfo-export-snippet (export-snippet contents info) +(defun org-texinfo-export-snippet (export-snippet _contents _info) "Transcode a EXPORT-SNIPPET object from Org to Texinfo. CONTENTS is nil. INFO is a plist holding contextual information." (when (eq (org-export-snippet-backend export-snippet) 'texinfo) @@ -727,17 +807,17 @@ CONTENTS is nil. INFO is a plist holding contextual information." ;;;; Fixed Width -(defun org-texinfo-fixed-width (fixed-width contents info) +(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" + (format "@example\n%s@end example" (org-remove-indentation (org-texinfo--sanitize-content (org-element-property :value fixed-width))))) ;;;; Footnote Reference -(defun org-texinfo-footnote-reference (footnote contents info) +(defun org-texinfo-footnote-reference (footnote _contents info) "Create a footnote reference for FOOTNOTE. FOOTNOTE is the footnote to define. CONTENTS is nil. INFO is a @@ -755,7 +835,7 @@ holding contextual information." (let* ((class (plist-get info :texinfo-class)) (level (org-export-get-relative-level headline info)) (numberedp (org-export-numbered-headline-p headline info)) - (class-sectioning (assoc class org-texinfo-classes)) + (class-sectioning (assoc class (plist-get info :texinfo-classes))) ;; Find the index type, if any. (index (org-element-property :INDEX headline)) ;; Create node info, to insert it before section formatting. @@ -788,20 +868,10 @@ holding contextual information." (org-export-get-tags headline info))) (priority (and (plist-get info :with-priority) (org-element-property :priority headline))) - (text (org-export-data (org-element-property :title headline) info)) - (full-text (if (not (eq org-texinfo-format-headline-function 'ignore)) - ;; User-defined formatting function. - (funcall org-texinfo-format-headline-function - todo todo-type priority text tags) - ;; Default formatting. - (concat - (when todo - (format "@strong{%s} " todo)) - (when priority (format "@emph{#%s} " priority)) - text - (when tags - (format " :%s:" - (mapconcat 'identity tags ":")))))) + (text (org-texinfo--sanitize-title + (org-element-property :title headline) info)) + (full-text (funcall (plist-get info :texinfo-format-headline-function) + todo todo-type priority text tags)) (contents (if (org-string-nw-p contents) (concat "\n" contents) ""))) (cond ;; Case 1: This is a footnote section: ignore it. @@ -835,9 +905,18 @@ holding contextual information." ;; Case 5: Standard headline. Export it as a section. (t (concat node (format section-fmt full-text contents)))))) +(defun org-texinfo-format-headline-default-function + (todo _todo-type priority text tags) + "Default format function for a headline. +See `org-texinfo-format-headline-function' for details." + (concat (when todo (format "@strong{%s} " todo)) + (when priority (format "@emph{#%s} " priority)) + text + (when tags (format " :%s:" (mapconcat 'identity tags ":"))))) + ;;;; Inline Src Block -(defun org-texinfo-inline-src-block (inline-src-block contents info) +(defun org-texinfo-inline-src-block (inline-src-block _contents _info) "Transcode an INLINE-SRC-BLOCK element from Org to Texinfo. CONTENTS holds the contents of the item. INFO is a plist holding contextual information." @@ -860,31 +939,27 @@ holding contextual information." (org-export-get-tags inlinetask info))) (priority (and (plist-get info :with-priority) (org-element-property :priority inlinetask)))) - ;; If `org-texinfo-format-inlinetask-function' is provided, call it - ;; with appropriate arguments. - (if (not (eq org-texinfo-format-inlinetask-function 'ignore)) - (funcall org-texinfo-format-inlinetask-function - todo todo-type priority title tags contents) - ;; Otherwise, use a default template. - (let ((full-title - (concat - (when todo (format "@strong{%s} " todo)) - (when priority (format "#%c " priority)) - title - (when tags (format ":%s:" - (mapconcat 'identity tags ":")))))) - (format (concat "@center %s\n\n" - "%s" - "\n") - full-title contents))))) + (funcall (plist-get info :texinfo-format-inlinetask-function) + todo todo-type priority title tags contents))) + +(defun org-texinfo-format-inlinetask-default-function + (todo _todo-type priority title tags contents) + "Default format function for a inlinetasks. +See `org-texinfo-format-inlinetask-function' for details." + (let ((full-title + (concat (when todo (format "@strong{%s} " todo)) + (when priority (format "#%c " priority)) + title + (when tags (format ":%s:" (mapconcat #'identity tags ":")))))) + (format "@center %s\n\n%s\n" full-title contents))) ;;;; Italic -(defun org-texinfo-italic (italic contents info) +(defun org-texinfo-italic (_italic contents info) "Transcode ITALIC from Org to Texinfo. CONTENTS is the text with italic markup. INFO is a plist holding contextual information." - (org-texinfo--text-markup contents 'italic)) + (org-texinfo--text-markup contents 'italic info)) ;;;; Item @@ -899,32 +974,51 @@ contextual information." ;;;; Keyword -(defun org-texinfo-keyword (keyword contents info) +(defun org-texinfo-keyword (keyword _contents info) "Transcode a KEYWORD element from Org to Texinfo. CONTENTS is nil. INFO is a plist holding contextual information." - (let ((key (org-element-property :key keyword)) - (value (org-element-property :value keyword))) - (cond - ((string= key "TEXINFO") value) - ((string= key "CINDEX") (format "@cindex %s" value)) - ((string= key "FINDEX") (format "@findex %s" value)) - ((string= key "KINDEX") (format "@kindex %s" value)) - ((string= key "PINDEX") (format "@pindex %s" value)) - ((string= key "TINDEX") (format "@tindex %s" value)) - ((string= key "VINDEX") (format "@vindex %s" value))))) + (let ((value (org-element-property :value keyword))) + (pcase (org-element-property :key keyword) + ("TEXINFO" value) + ("CINDEX" (format "@cindex %s" value)) + ("FINDEX" (format "@findex %s" value)) + ("KINDEX" (format "@kindex %s" value)) + ("PINDEX" (format "@pindex %s" value)) + ("TINDEX" (format "@tindex %s" value)) + ("VINDEX" (format "@vindex %s" value)) + ("TOC" + (cond ((string-match-p "\\<tables\\>" value) + (concat "@listoffloats " + (org-export-translate "Table" :utf-8 info))) + ((string-match-p "\\<listings\\>" value) + (concat "@listoffloats " + (org-export-translate "Listing" :utf-8 info)))))))) ;;;; Line Break -(defun org-texinfo-line-break (line-break contents info) +(defun org-texinfo-line-break (_line-break _contents _info) "Transcode a LINE-BREAK object from Org to Texinfo. CONTENTS is nil. INFO is a plist holding contextual information." "@*\n") ;;;; Link +(defun org-texinfo--@ref (datum description info) + "Return @ref command for element or object DATUM. +DESCRIPTION is the name of the section to print, as a string." + (let ((node-name (org-texinfo--get-node datum info)) + ;; Sanitize DESCRIPTION for cross-reference use. In + ;; particular, remove colons as they seem to cause (even + ;; within @asis{...} to the Texinfo reader. + (title (replace-regexp-in-string + "[ \t]*:+" "" + (replace-regexp-in-string "," "@comma{}" description)))) + (if (equal title node-name) + (format "@ref{%s}" node-name) + (format "@ref{%s, , %s}" node-name title)))) + (defun org-texinfo-link (link desc info) "Transcode a LINK object from Org to Texinfo. - DESC is the description part of the link, or the empty string. INFO is a plist holding contextual information. See `org-export-data'." @@ -935,78 +1029,99 @@ INFO is a plist holding contextual information. See (path (cond ((member type '("http" "https" "ftp")) (concat type ":" raw-path)) - ((and (string= type "file") (file-name-absolute-p raw-path)) - (concat "file:" raw-path)) - (t raw-path))) - protocol) + ((string= type "file") (org-export-file-uri raw-path)) + (t raw-path)))) (cond + ((org-export-custom-protocol-maybe link desc 'texinfo)) + ((org-export-inline-image-p link org-texinfo-inline-image-rules) + (org-texinfo--inline-image link info)) ((equal type "radio") (let ((destination (org-export-resolve-radio-link link info))) (if (not destination) desc - (format "@ref{%s,,%s}" - (org-texinfo--get-node destination info) - desc)))) + (org-texinfo--@ref destination desc info)))) ((member type '("custom-id" "id" "fuzzy")) (let ((destination (if (equal type "fuzzy") (org-export-resolve-fuzzy-link link info) (org-export-resolve-id-link link info)))) - (case (org-element-type destination) - ((nil) + (pcase (org-element-type destination) + (`nil (format org-texinfo-link-with-unknown-path-format (org-texinfo--sanitize-content path))) ;; Id link points to an external file. - (plain-text + (`plain-text (if desc (format "@uref{file://%s,%s}" destination desc) (format "@uref{file://%s}" destination))) - (headline - (format "@ref{%s,%s}" - (org-texinfo--get-node destination info) - (cond - (desc) - ((org-export-numbered-headline-p destination info) - (org-export-data - (org-element-property :title destination) info)) - (t - (mapconcat - #'number-to-string - (org-export-get-headline-number destination info) "."))))) - (otherwise - (let ((topic - (or desc - (if (and (eq (org-element-type destination) 'headline) - (not (org-export-numbered-headline-p - destination info))) - (org-export-data - (org-element-property :title destination) info)) - (let ((n (org-export-get-ordinal destination info))) - (cond - ((not n) nil) - ((integerp n) n) - (t (mapconcat #'number-to-string n "."))))))) - (when topic - (format "@ref{%s,,%s}" - (org-texinfo--get-node destination info) - topic))))))) + ((or `headline + ;; Targets within headlines cannot be turned into + ;; @anchor{}, so we refer to the headline parent + ;; directly. + (and `target + (guard (eq 'headline + (org-element-type + (org-element-property :parent destination)))))) + (let ((headline (org-element-lineage destination '(headline) t))) + (org-texinfo--@ref + headline + (or desc (org-texinfo--sanitize-title + (org-element-property :title headline) info)) + info))) + (_ + (org-texinfo--@ref + destination + (or desc + (pcase (org-export-get-ordinal destination info) + ((and (pred integerp) n) (number-to-string n)) + ((and (pred consp) n) (mapconcat #'number-to-string n ".")) + (_ "???"))) + info))))) ;cannot guess the description ((equal type "info") (let* ((info-path (split-string path "[:#]")) (info-manual (car info-path)) - (info-node (or (cadr info-path) "top")) + (info-node (or (cadr info-path) "Top")) (title (or desc ""))) (format "@ref{%s,%s,,%s,}" info-node title info-manual))) ((string= type "mailto") (format "@email{%s}" (concat (org-texinfo--sanitize-content path) - (and desc (concat "," desc))))) - ((let ((protocol (nth 2 (assoc type org-link-protocols)))) - (and (functionp protocol) - (funcall protocol (org-link-unescape path) desc 'texinfo)))) + (and desc (concat ", " desc))))) ;; External link with a description part. - ((and path desc) (format "@uref{%s,%s}" path desc)) + ((and path desc) (format "@uref{%s, %s}" path desc)) ;; External link without a description part. (path (format "@uref{%s}" path)) ;; No path, only description. Try to do something useful. - (t (format org-texinfo-link-with-unknown-path-format desc))))) + (t + (format (plist-get info :texinfo-link-with-unknown-path-format) desc))))) + +(defun org-texinfo--inline-image (link info) + "Return Texinfo code for an inline image. +LINK is the link pointing to the inline image. INFO is the +current state of the export, as a plist." + (let* ((parent (org-export-get-parent-element link)) + (label (and (org-element-property :name parent) + (org-texinfo--get-node parent info))) + (caption (org-export-get-caption parent)) + (shortcaption (org-export-get-caption parent t)) + (path (org-element-property :path link)) + (filename + (file-name-sans-extension + (if (file-name-absolute-p path) (expand-file-name path) path))) + (extension (file-name-extension path)) + (attributes (org-export-read-attribute :attr_texinfo parent)) + (height (or (plist-get attributes :height) "")) + (width (or (plist-get attributes :width) "")) + (alt (or (plist-get attributes :alt) "")) + (image (format "@image{%s,%s,%s,%s,%s}" + filename width height alt extension))) + (cond ((or caption shortcaption) + (org-texinfo--wrap-float image + info + (org-export-translate "Figure" :utf-8 info) + label + caption + shortcaption)) + (label (concat "@anchor{" label "}\n" image)) + (t image)))) ;;;; Menu @@ -1058,7 +1173,7 @@ is an integer, build the menu recursively, down to this depth." (org-export-data (org-export-get-alt-title h info) info) (org-texinfo--format-entries entries info)) (org-texinfo--build-menu h info (1- level)))))) - (org-texinfo--menu-entries scope info) ""))))) + (org-texinfo--menu-entries scope info) "\n"))))) (defun org-texinfo--format-entries (entries info) "Format all direct menu entries in SCOPE, as a string. @@ -1067,8 +1182,13 @@ a plist containing contextual information." (org-element-normalize-string (mapconcat (lambda (h) - (let* ((title (org-export-data - (org-export-get-alt-title h info) info)) + (let* ((title + ;; Colons are used as a separator between title and node + ;; name. Remove them. + (replace-regexp-in-string + "[ \t]+:+" "" + (org-texinfo--sanitize-title + (org-export-get-alt-title h info) info))) (node (org-texinfo--get-node h info)) (entry (concat "* " title ":" (if (string= title node) ":" @@ -1099,9 +1219,20 @@ holding contextual information." info nil 'headline) cache)))) +;;;; Node Property + +(defun org-texinfo-node-property (node-property _contents _info) + "Transcode a NODE-PROPERTY element from Org to Texinfo. +CONTENTS is nil. INFO is a plist holding contextual +information." + (format "%s:%s" + (org-element-property :key node-property) + (let ((value (org-element-property :value node-property))) + (if value (concat " " value) "")))) + ;;;; 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." @@ -1114,7 +1245,10 @@ the plist used as a communication channel." CONTENTS is the contents of the list. INFO is a plist holding contextual information." (let* ((attr (org-export-read-attribute :attr_texinfo plain-list)) - (indic (or (plist-get attr :indic) org-texinfo-def-table-markup)) + (indic (let ((i (or (plist-get attr :indic) + (plist-get info :texinfo-def-table-markup)))) + ;; Allow indicating commands with missing @ sign. + (if (string-prefix-p "@" i) i (concat "@" i)))) (table-type (plist-get attr :table-type)) (type (org-element-property :type plain-list)) (list-type (cond @@ -1141,16 +1275,14 @@ contextual information." (setq output (org-export-activate-smart-quotes output :texinfo info text))) ;; LaTeX into @LaTeX{} and TeX into @TeX{} - (let ((case-fold-search nil) - (start 0)) - (while (string-match "\\(\\(?:La\\)?TeX\\)" output start) - (setq output (replace-match - (format "@%s{}" (match-string 1 output)) nil t output) - start (match-end 0)))) + (let ((case-fold-search nil)) + (setq output (replace-regexp-in-string "\\(?:La\\)?TeX" "@\\&{}" output))) ;; Convert special strings. (when (plist-get info :with-special-strings) - (while (string-match (regexp-quote "...") output) - (setq output (replace-match "@dots{}" nil t output)))) + (setq output + (replace-regexp-in-string + "\\.\\.\\." "@dots{}" + (replace-regexp-in-string "\\\\-" "@-" output)))) ;; Handle break preservation if required. (when (plist-get info :preserve-breaks) (setq output (replace-regexp-in-string @@ -1160,7 +1292,7 @@ contextual information." ;;;; Planning -(defun org-texinfo-planning (planning contents info) +(defun org-texinfo-planning (planning _contents info) "Transcode a PLANNING element from Org to Texinfo. CONTENTS is nil. INFO is a plist holding contextual information." @@ -1174,39 +1306,35 @@ information." (when closed (concat (format "@strong{%s} " org-closed-string) - (format org-texinfo-inactive-timestamp-format - (org-translate-time - (org-element-property :raw-value closed)))))) + (format (plist-get info :texinfo-inactive-timestamp-format) + (org-timestamp-translate closed))))) (let ((deadline (org-element-property :deadline planning))) (when deadline (concat (format "@strong{%s} " org-deadline-string) - (format org-texinfo-active-timestamp-format - (org-translate-time - (org-element-property :raw-value deadline)))))) + (format (plist-get info :texinfo-active-timestamp-format) + (org-timestamp-translate deadline))))) (let ((scheduled (org-element-property :scheduled planning))) (when scheduled (concat (format "@strong{%s} " org-scheduled-string) - (format org-texinfo-active-timestamp-format - (org-translate-time - (org-element-property :raw-value scheduled)))))))) + (format (plist-get info :texinfo-active-timestamp-format) + (org-timestamp-translate scheduled))))))) " ") "@*")) ;;;; Property Drawer -(defun org-texinfo-property-drawer (property-drawer contents info) +(defun org-texinfo-property-drawer (_property-drawer contents _info) "Transcode a PROPERTY-DRAWER element from Org to Texinfo. -CONTENTS is nil. INFO is a plist holding contextual -information." - ;; The property drawer isn't exported but we want separating blank - ;; lines nonetheless. - "") +CONTENTS holds the contents of the drawer. INFO is a plist +holding contextual information." + (and (org-string-nw-p contents) + (format "@verbatim\n%s@end verbatim" contents))) ;;;; Quote Block -(defun org-texinfo-quote-block (quote-block contents info) +(defun org-texinfo-quote-block (quote-block contents _info) "Transcode a QUOTE-BLOCK element from Org to Texinfo. CONTENTS holds the contents of the block. INFO is a plist holding contextual information." @@ -1216,15 +1344,6 @@ holding contextual information." (format " %s" title))))) (format "%s\n%s@end quotation" start-quote contents))) -;;;; Quote Section - -(defun org-texinfo-quote-section (quote-section contents info) - "Transcode a QUOTE-SECTION element from Org to Texinfo. -CONTENTS is nil. INFO is a plist holding contextual information." - (let ((value (org-remove-indentation - (org-element-property :value quote-section)))) - (when value (format "@verbatim\n%s@end verbatim" value)))) - ;;;; Radio Target (defun org-texinfo-radio-target (radio-target text info) @@ -1232,8 +1351,7 @@ CONTENTS is nil. INFO is a plist holding contextual information." TEXT is the text of the target. INFO is a plist holding contextual information." (format "@anchor{%s}%s" - (org-export-solidify-link-text - (org-element-property :value radio-target)) + (org-texinfo--get-node radio-target info) text)) ;;;; Section @@ -1242,40 +1360,67 @@ contextual information." "Transcode a SECTION element from Org to Texinfo. CONTENTS holds the contents of the section. INFO is a plist holding contextual information." - (concat contents - (let ((parent (org-export-get-parent-headline section))) - (and parent (org-texinfo-make-menu parent info))))) + (let ((parent (org-export-get-parent-headline section))) + (when parent ;ignore very first section + (org-trim + (concat contents "\n" (org-texinfo-make-menu parent info)))))) ;;;; Special Block -(defun org-texinfo-special-block (special-block contents info) +(defun org-texinfo-special-block (special-block contents _info) "Transcode a SPECIAL-BLOCK element from Org to Texinfo. CONTENTS holds the contents of the block. INFO is a plist used as a communication channel." - contents) + (let ((opt (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))) ;;;; Src Block -(defun org-texinfo-src-block (src-block contents info) +(defun org-texinfo-src-block (src-block _contents info) "Transcode a SRC-BLOCK element from Org to Texinfo. CONTENTS holds the contents of the item. INFO is a plist holding contextual information." - (let ((lispp (org-string-match-p "lisp" - (org-element-property :language src-block))) - (code (org-texinfo--sanitize-content - (org-export-format-code-default src-block info)))) - (format (if lispp "@lisp\n%s@end lisp" "@example\n%s@end example") code))) + (let* ((lisp (string-match-p "lisp" + (org-element-property :language src-block))) + (code (org-texinfo--sanitize-content + (org-export-format-code-default src-block info))) + (value (format + (if lisp "@lisp\n%s@end lisp" "@example\n%s@end example") + code)) + (caption (org-export-get-caption src-block)) + (shortcaption (org-export-get-caption src-block t))) + (if (not (or caption shortcaption)) value + (org-texinfo--wrap-float value + info + (org-export-translate "Listing" :utf-8 info) + (org-texinfo--get-node src-block info) + caption + shortcaption)))) ;;;; Statistics Cookie -(defun org-texinfo-statistics-cookie (statistics-cookie contents info) +(defun org-texinfo-statistics-cookie (statistics-cookie _contents _info) "Transcode a STATISTICS-COOKIE object from Org to Texinfo. CONTENTS is nil. INFO is a plist holding contextual information." (org-element-property :value statistics-cookie)) + +;;;; Strike-through + +(defun org-texinfo-strike-through (_strike-through contents info) + "Transcode STRIKE-THROUGH from Org to Texinfo. +CONTENTS is the text with strike-through markup. INFO is a plist +holding contextual information." + (org-texinfo--text-markup contents 'strike-through info)) + ;;;; Subscript -(defun org-texinfo-subscript (subscript contents info) +(defun org-texinfo-subscript (_subscript contents _info) "Transcode a SUBSCRIPT object from Org to Texinfo. CONTENTS is the contents of the object. INFO is a plist holding contextual information." @@ -1283,7 +1428,7 @@ contextual information." ;;;; Superscript -(defun org-texinfo-superscript (superscript contents info) +(defun org-texinfo-superscript (_superscript contents _info) "Transcode a SUPERSCRIPT object from Org to Texinfo. CONTENTS is the contents of the object. INFO is a plist holding contextual information." @@ -1302,10 +1447,19 @@ contextual information." (let* ((col-width (org-export-read-attribute :attr_texinfo table :columns)) (columns (if col-width (format "@columnfractions %s" col-width) - (org-texinfo-table-column-widths table info)))) - (format "@multitable %s\n%s@end multitable" - columns - contents)))) + (org-texinfo-table-column-widths table info))) + (caption (org-export-get-caption table)) + (shortcaption (org-export-get-caption table t)) + (table-str (format "@multitable %s\n%s@end multitable" + columns + contents))) + (if (not (or caption shortcaption)) table-str + (org-texinfo--wrap-float table-str + info + (org-export-translate "Table" :utf-8 info) + (org-texinfo--get-node table info) + caption + shortcaption))))) (defun org-texinfo-table-column-widths (table info) "Determine the largest table cell in each column to process alignment. @@ -1324,7 +1478,7 @@ a communication channel." (let ((w (- (org-element-property :contents-end cell) (org-element-property :contents-begin cell)))) (aset widths idx (max w (aref widths idx)))) - (incf idx)) + (cl-incf idx)) info))) info) (format "{%s}" (mapconcat (lambda (w) (make-string w ?a)) widths "} {")))) @@ -1335,16 +1489,18 @@ a communication channel." "Transcode a TABLE-CELL element from Org to Texinfo. CONTENTS is the cell contents. INFO is a plist used as a communication channel." - (concat (if (and contents - org-texinfo-table-scientific-notation - (string-match orgtbl-exp-regexp contents)) - ;; Use appropriate format string for scientific - ;; notation. - (format org-texinfo-table-scientific-notation - (match-string 1 contents) - (match-string 2 contents)) - contents) - (when (org-export-get-next-element table-cell info) "\n@tab "))) + (concat + (let ((scientific-notation + (plist-get info :texinfo-table-scientific-notation))) + (if (and contents + scientific-notation + (string-match orgtbl-exp-regexp contents)) + ;; Use appropriate format string for scientific notation. + (format scientific-notation + (match-string 1 contents) + (match-string 2 contents)) + contents)) + (when (org-export-get-next-element table-cell info) "\n@tab "))) ;;;; Table Row @@ -1365,39 +1521,47 @@ a communication channel." ;;;; Target -(defun org-texinfo-target (target contents info) +(defun org-texinfo-target (target _contents info) "Transcode a TARGET object from Org to Texinfo. CONTENTS is nil. INFO is a plist holding contextual information." - (format "@anchor{%s}" - (org-export-solidify-link-text (org-element-property :value target)))) + (format "@anchor{%s}" (org-texinfo--get-node target info))) ;;;; Timestamp -(defun org-texinfo-timestamp (timestamp contents info) +(defun org-texinfo-timestamp (timestamp _contents info) "Transcode a TIMESTAMP object from Org to Texinfo. CONTENTS is nil. INFO is a plist holding contextual information." (let ((value (org-texinfo-plain-text (org-timestamp-translate timestamp) info))) - (case (org-element-property :type timestamp) - ((active active-range) - (format org-texinfo-active-timestamp-format value)) - ((inactive inactive-range) - (format org-texinfo-inactive-timestamp-format value)) - (t (format org-texinfo-diary-timestamp-format value))))) + (pcase (org-element-property :type timestamp) + ((or `active `active-range) + (format (plist-get info :texinfo-active-timestamp-format) value)) + ((or `inactive `inactive-range) + (format (plist-get info :texinfo-inactive-timestamp-format) value)) + (_ (format (plist-get info :texinfo-diary-timestamp-format) value))))) + +;;;; Underline + +(defun org-texinfo-underline (_underline contents info) + "Transcode UNDERLINE from Org to Texinfo. +CONTENTS is the text with underline markup. INFO is a plist +holding contextual information." + (org-texinfo--text-markup contents 'underline info)) ;;;; Verbatim -(defun org-texinfo-verbatim (verbatim contents info) +(defun org-texinfo-verbatim (verbatim _contents info) "Transcode a VERBATIM object from Org to Texinfo. CONTENTS is nil. INFO is a plist used as a communication channel." - (org-texinfo--text-markup (org-element-property :value verbatim) 'verbatim)) + (org-texinfo--text-markup + (org-element-property :value verbatim) 'verbatim 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." @@ -1436,7 +1600,7 @@ file-local settings. Return output file's name." (interactive) (let ((outfile (org-export-output-file-name ".texi" subtreep)) - (org-export-coding-system `,org-texinfo-coding-system)) + (org-export-coding-system org-texinfo-coding-system)) (org-export-to-file 'texinfo outfile async subtreep visible-only body-only ext-plist))) @@ -1473,7 +1637,7 @@ directory. Return INFO file's name." (interactive) (let ((outfile (org-export-output-file-name ".texi" subtreep)) - (org-export-coding-system `,org-texinfo-coding-system)) + (org-export-coding-system org-texinfo-coding-system)) (org-export-to-file 'texinfo outfile async subtreep visible-only body-only ext-plist (lambda (file) (org-texinfo-compile file))))) @@ -1491,99 +1655,36 @@ Return output file name." ;;;###autoload (defun org-texinfo-convert-region-to-texinfo () - "Assume the current region has org-mode syntax, and convert it to Texinfo. + "Assume the current region has Org syntax, and convert it to Texinfo. This can be used in any buffer. For example, you can write an -itemized list in org-mode syntax in an Texinfo buffer and use -this command to convert it." +itemized list in Org syntax in an Texinfo buffer and use this +command to convert it." (interactive) (org-export-replace-region-by 'texinfo)) (defun org-texinfo-compile (file) "Compile a texinfo file. -FILE is the name of the file being compiled. Processing is -done through the command specified in `org-texinfo-info-process'. +FILE is the name of the file being compiled. Processing is done +through the command specified in `org-texinfo-info-process', +which see. Output is redirected to \"*Org INFO Texinfo Output*\" +buffer. Return INFO file name or an error if it couldn't be produced." - (let* ((base-name (file-name-sans-extension (file-name-nondirectory file))) - (full-name (file-truename file)) - (out-dir (file-name-directory file)) - ;; Properly set working directory for compilation. - (default-directory (if (file-name-absolute-p file) - (file-name-directory full-name) - default-directory)) - errors) - (message "Processing Texinfo file %s..." file) - (save-window-excursion - ;; Replace %b, %f and %o with appropriate values in each command - ;; before applying it. Output is redirected to "*Org INFO - ;; Texinfo Output*" buffer. - (let ((outbuf (get-buffer-create "*Org INFO Texinfo Output*"))) - (dolist (command org-texinfo-info-process) - (shell-command - (replace-regexp-in-string - "%b" (shell-quote-argument base-name) - (replace-regexp-in-string - "%f" (shell-quote-argument full-name) - (replace-regexp-in-string - "%o" (shell-quote-argument out-dir) command t t) t t) t t) - outbuf)) - ;; Collect standard errors from output buffer. - (setq errors (org-texinfo-collect-errors outbuf))) - (let ((infofile (concat out-dir base-name ".info"))) - ;; Check for process failure. Provide collected errors if - ;; possible. - (if (not (file-exists-p infofile)) - (error "INFO file %s wasn't produced%s" infofile - (if errors (concat ": " errors) "")) - ;; Else remove log files, when specified, and signal end of - ;; process to user, along with any error encountered. - (when org-texinfo-remove-logfiles - (dolist (ext org-texinfo-logfiles-extensions) - (let ((file (concat out-dir base-name "." ext))) - (when (file-exists-p file) (delete-file file))))) - (message (concat "Process completed" - (if (not errors) "." - (concat " with errors: " errors))))) - ;; Return output file name. - infofile)))) - -(defun org-texinfo-collect-errors (buffer) - "Collect some kind of errors from \"makeinfo\" command output. - -BUFFER is the buffer containing output. - -Return collected error types as a string, or nil if there was -none." - (with-current-buffer buffer - (save-excursion - (goto-char (point-min)) - ;; Find final "makeinfo" run. - (when t - (let ((case-fold-search t) - (errors "")) - (when (save-excursion - (re-search-forward "perhaps incorrect sectioning?" nil t)) - (setq errors (concat errors " [incorrect sectioning]"))) - (when (save-excursion - (re-search-forward "missing close brace" nil t)) - (setq errors (concat errors " [syntax error]"))) - (when (save-excursion - (re-search-forward "Unknown command" nil t)) - (setq errors (concat errors " [undefined @command]"))) - (when (save-excursion - (re-search-forward "No matching @end" nil t)) - (setq errors (concat errors " [block incomplete]"))) - (when (save-excursion - (re-search-forward "requires a sectioning" nil t)) - (setq errors (concat errors " [invalid section command]"))) - (when (save-excursion - (re-search-forward "\\[unexpected\ ]" nil t)) - (setq errors (concat errors " [unexpected error]"))) - (when (save-excursion - (re-search-forward "misplaced " nil t)) - (setq errors (concat errors " [syntax error]"))) - (and (org-string-nw-p errors) (org-trim errors))))))) + (message "Processing Texinfo file %s..." file) + (let* ((log-name "*Org INFO Texinfo Output*") + (log (get-buffer-create log-name)) + (output + (org-compile-file file org-texinfo-info-process "info" + (format "See %S for details" log-name) + log))) + (when org-texinfo-remove-logfiles + (let ((base (file-name-sans-extension output))) + (dolist (ext org-texinfo-logfiles-extensions) + (let ((file (concat base "." ext))) + (when (file-exists-p file) (delete-file file)))))) + (message "Process completed.") + output)) (provide 'ox-texinfo) |