* [PATCH] New LaTeX code export option: engraved @ 2022-05-04 15:59 Timothy 2022-05-05 7:52 ` Daniel Fleischer ` (3 more replies) 0 siblings, 4 replies; 27+ messages in thread From: Timothy @ 2022-05-04 15:59 UTC (permalink / raw) To: emacs-orgmode, Daniel Fleischer, Nicolas Goaziou [-- Attachment #1.1: Type: text/plain, Size: 3432 bytes --] Hi All, I’ve been fairly busy as of late (hence my recent silence on this ML), however I have a patchset that’s been in the works for a while that I’ve finally polished up. Short version: It adds a new (superior) option for exporting code blocks with syntax highlighting to LaTeX. The long version follows. Currently there are four options for exporting code to LaTeX (ordered by complexity/quality). 1. Verbatim, which simply includes the code unstyled 2. Custom, which puts the code in an enviroment of your choice 3. Listings, which uses the LaTeX package by this name. This is quick, but exceedingly basic. 4. Minted, which uses the LaTeX package by this name. This is slow, but produces better results than Listings This patchset accomplishes two things: 1. It refactors the overly large `org-latex-src-block' function, and makes a few other improvements to pre-existing code 2. It adds a new option for exporting code, named (you guessed it!) “engraved” What is this new option, and why do we want it? About a year ago I started work on a package that generalises the functionality of `htmlize.el', termed `engrave-faces' (<https://elpa.gnu.org/packages/engrave-faces.html>). It provides the ability to extract font-lock information and export it to a number of formats: html, ansi, and (crucially) LaTeX! Since the LaTeX export is built on the `fvextra' (LaTeX) package (like pygments), the vast majority of the Minted options you’re used to just carry over. This allows for a result that is, I think, straight up better than all the pre-existing options. For starters, you can now apply syntax highlighting to any language you have a major mode for. There are a number of optimisations unattempted, but it already significantly outperforms Minted. Here are some timings from my `config.org': ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ LaTeX code backend Compile time Overhead Overhead ratio ──────────────────────────────────────────────────────────── verbatim 12 s 0 0.0 lstlistings 15 s 3 s 0.2 Engrave 34 s 22 s 1.8 Pygments (Minted) 184 s 172 s 14.3 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Compared to Minted, we also no longer have to install `pygments' or pass the `--shelll-escape' flag to LaTeX to generate passable code blocks. Having an all-emacs system also allows for some nifty things, like having entire documents/presentations based on your Emacs theme (see <https://github.com/tecosaur/ox-chameleon>). Demo images: <https://0x0.st/oAl1.png>, <https://0x0.st/oAle.png>. Here are some more screenshots to see what the result can look like in practice: • <https://0x0.st/oAl2.png> • <https://0x0.st/oAl_.png> • <https://0x0.st/oAlL.png> So, please take a look at the patches, give this a whirl, and let me know what you think! 😀 All the best, Timothy [-- Attachment #1.2: Type: text/html, Size: 14197 bytes --] [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-ox-latex-Refactor-org-latex-src-block.patch --] [-- Type: text/x-patch, Size: 15943 bytes --] From 87872cc8f2fb1da1a03dc4aadfbd4af6541d8c13 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 14:35:34 +0800 Subject: [PATCH 1/4] ox-latex: Refactor `org-latex-src-block' * lisp/ox-latex.el (org-latex-src-block): Extract the per-format logic from `org-latex-src-block' into new dedicated functions: + `org-latex-src-block--verbatim' + `org-latex-src-block--custom' + `org-latex-src-block--minted' + `org-latex-src-block--listings' This makes `org-latex-src-block' much less monolithic, taking it from 175 lines to 30, and I find also makes it easier to understand. --- lisp/ox-latex.el | 339 ++++++++++++++++++++++++++--------------------- 1 file changed, 185 insertions(+), 154 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 841ad48bc..63855d2f6 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2997,164 +2997,195 @@ (defun org-latex-src-block (src-block _contents info) (float (plist-get attributes :float)) (listings (plist-get info :latex-listings))) (cond - ;; Case 1. No source fontification. ((or (not lang) (not listings)) - (let ((caption-str (org-latex--caption/label-string src-block info)) - (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" - (org-export-format-code-default src-block info)))) - (cond ((string= "multicolumn" float) - (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" - (plist-get info :latex-default-figure-position) - (if caption-above-p caption-str "") - verbatim - (if caption-above-p "" caption-str))) - (caption (concat - (if caption-above-p caption-str "") - verbatim - (if caption-above-p "" (concat "\n" caption-str)))) - (t verbatim)))) - ;; Case 2. Custom environment. + (org-latex-src-block--verbatim src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) (custom-env - (let ((caption-str (org-latex--caption/label-string src-block info)) - (formatted-src (org-export-format-code-default src-block info))) - (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) - (format "\\begin{%s}\n%s\\end{%s}\n" - custom-env - (concat (and caption-above-p caption-str) - formatted-src - (and (not caption-above-p) caption-str)) - custom-env) - (format-spec custom-env - `((?s . ,formatted-src) - (?c . ,caption) - (?f . ,float) - (?l . ,(org-latex--label src-block info)) - (?o . ,(or (plist-get attributes :options) ""))))))) - ;; Case 3. Use minted package. + (org-latex-src-block--custom src-block info lang caption caption-above-p label + num-start retain-labels attributes float custom-env)) ((eq listings 'minted) - (let* ((caption-str (org-latex--caption/label-string src-block info)) - (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) - (plist-get info :latex-default-figure-position))) - (float-env - (cond - ((string= "multicolumn" float) - (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - (caption - (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - ((string= "t" float) - (concat (format "\\begin{listing}[%s]\n" - placement) - "%s\n\\end{listing}")) - (t "%s"))) - (options (plist-get info :latex-minted-options)) - (body - (format - "\\begin{minted}[%s]{%s}\n%s\\end{minted}" - ;; Options. - (concat - (org-latex--make-option-string - (if (or (not num-start) (assoc "linenos" options)) - options - (append - `(("linenos") - ("firstnumber" ,(number-to-string (1+ num-start)))) - options))) - (let ((local-options (plist-get attributes :options))) - (and local-options (concat "," local-options)))) - ;; Language. - (or (cadr (assq (intern lang) - (plist-get info :latex-minted-langs))) - (downcase lang)) - ;; Source code. - (let* ((code-info (org-export-unravel-code src-block)) - (max-width - (apply 'max - (mapcar 'length - (org-split-string (car code-info) - "\n"))))) - (org-export-format-code - (car code-info) - (lambda (loc _num ref) - (concat - loc - (when ref - ;; Ensure references are flushed to the right, - ;; separated with 6 spaces from the widest line - ;; of code. - (concat (make-string (+ (- max-width (length loc)) 6) - ?\s) - (format "(%s)" ref))))) - nil (and retain-labels (cdr code-info))))))) - ;; Return value. - (format float-env body))) - ;; Case 4. Use listings package. + (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) (t - (let ((lst-lang - (or (cadr (assq (intern lang) - (plist-get info :latex-listings-langs))) - lang)) - (caption-str - (when caption - (let ((main (org-export-get-caption src-block)) - (secondary (org-export-get-caption src-block t))) - (if (not secondary) - (format "{%s}" (org-export-data main info)) - (format "{[%s]%s}" - (org-export-data secondary info) - (org-export-data main info)))))) - (lst-opt (plist-get info :latex-listings-options))) - (concat - ;; Options. - (format - "\\lstset{%s}\n" - (concat - (org-latex--make-option-string - (append - lst-opt - (cond - ((and (not float) (plist-member attributes :float)) nil) - ((string= "multicolumn" float) '(("float" "*"))) - ((and float (not (assoc "float" lst-opt))) - `(("float" ,(plist-get info :latex-default-figure-position))))) - `(("language" ,lst-lang)) - (if label - `(("label" ,(org-latex--label src-block info))) - '(("label" " "))) - (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) - `(("captionpos" ,(if caption-above-p "t" "b"))) - (cond ((assoc "numbers" lst-opt) nil) - ((not num-start) '(("numbers" "none"))) - (t `(("firstnumber" ,(number-to-string (1+ num-start))) - ("numbers" "left")))))) - (let ((local-options (plist-get attributes :options))) - (and local-options (concat "," local-options))))) - ;; Source code. - (format - "\\begin{lstlisting}\n%s\\end{lstlisting}" - (let* ((code-info (org-export-unravel-code src-block)) - (max-width - (apply 'max - (mapcar 'length - (org-split-string (car code-info) "\n"))))) - (org-export-format-code - (car code-info) - (lambda (loc _num ref) - (concat - loc - (when ref - ;; Ensure references are flushed to the right, - ;; separated with 6 spaces from the widest line of - ;; code - (concat (make-string (+ (- max-width (length loc)) 6) ?\s) - (format "(%s)" ref))))) - nil (and retain-labels (cdr code-info)))))))))))) - + (org-latex-src-block--listings src-block info lang caption caption-above-p label + num-start retain-labels attributes float)))))) + +(defun org-latex-src-block--verbatim + (src-block info _lang caption caption-above-p _label + _num-start _retain-labels _attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using verbatim. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((caption-str (org-latex--caption/label-string src-block info)) + (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" + (org-export-format-code-default src-block info)))) + (cond ((string= "multicolumn" float) + (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" + (plist-get info :latex-default-figure-position) + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" caption-str))) + (caption (concat + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" (concat "\n" caption-str)))) + (t verbatim)))) + +(defun org-latex-src-block--custom + (src-block info _lang caption caption-above-p _label + _num-start _retain-labels attributes float custom-env) + "Transcode a SRC-BLOCK element from Org to LaTeX, using a custom environment. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((caption-str (org-latex--caption/label-string src-block info)) + (formatted-src (org-export-format-code-default src-block info))) + (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) + (format "\\begin{%s}\n%s\\end{%s}\n" + custom-env + (concat (and caption-above-p caption-str) + formatted-src + (and (not caption-above-p) caption-str)) + custom-env) + (format-spec custom-env + `((?s . ,formatted-src) + (?c . ,caption) + (?f . ,float) + (?l . ,(org-latex--label src-block info)) + (?o . ,(or (plist-get attributes :options) ""))))))) + +(defun org-latex-src-block--minted + (src-block info _lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using minted. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-minted-options)) + (body + (format + "\\begin{minted}[%s]{%s}\n%s\\end{minted}" + ;; Options. + (concat + (org-latex--make-option-string + (if (or (not num-start) (assoc "linenos" options)) + options + (append + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start)))) + options))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options)))) + ;; Language. + (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase lang)) + ;; Source code. + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))))) + ;; Return value. + (format float-env body))) + +(defun org-latex-src-block--listings + (src-block info lang caption caption-above-p label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using listings. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((lst-lang + (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + lang)) + (caption-str + (when caption + (let ((main (org-export-get-caption src-block)) + (secondary (org-export-get-caption src-block t))) + (if (not secondary) + (format "{%s}" (org-export-data main info)) + (format "{[%s]%s}" + (org-export-data secondary info) + (org-export-data main info)))))) + (lst-opt (plist-get info :latex-listings-options))) + (concat + ;; Options. + (format + "\\lstset{%s}\n" + (concat + (org-latex--make-option-string + (append + lst-opt + (cond + ((and (not float) (plist-member attributes :float)) nil) + ((string= "multicolumn" float) '(("float" "*"))) + ((and float (not (assoc "float" lst-opt))) + `(("float" ,(plist-get info :latex-default-figure-position))))) + `(("language" ,lst-lang)) + (if label + `(("label" ,(org-latex--label src-block info))) + '(("label" " "))) + (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) + `(("captionpos" ,(if caption-above-p "t" "b"))) + (cond ((assoc "numbers" lst-opt) nil) + ((not num-start) '(("numbers" "none"))) + (t `(("firstnumber" ,(number-to-string (1+ num-start))) + ("numbers" "left")))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options))))) + ;; Source code. + (format + "\\begin{lstlisting}\n%s\\end{lstlisting}" + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line of + ;; code + (concat (make-string (+ (- max-width (length loc)) 6) ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info)))))))) ;;;; Statistics Cookie -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-ox-latex-Refactor-org-latex-inline-src-block.patch --] [-- Type: text/x-patch, Size: 3727 bytes --] From a4d833418c3e2f0a8f365b92c01c091f75b6482d Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 4 May 2022 18:53:10 +0800 Subject: [PATCH 2/4] ox-latex: Refactor `org-latex-inline-src-block' * lisp/ox-latex.el (org-latex-inline-src-block, org-latex-inline-src-block--minted, org-latex-inline-src-block--listings): Extract the minted and listings specific logic out of `org-latex-inline-src-block` into the new functions `org-latex-inline-src-block--minted` and `org-latex-inline-src-block--listings`. --- lisp/ox-latex.el | 58 +++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 63855d2f6..ed66a51c0 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2127,36 +2127,34 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) "Transcode an INLINE-SRC-BLOCK element from Org to LaTeX. CONTENTS holds the contents of the item. INFO is a plist holding contextual information." - (let* ((code (org-element-property :value inline-src-block)) - (separator (org-latex--find-verb-separator code))) - (cl-case (plist-get info :latex-listings) - ;; Do not use a special package: transcode it verbatim, as code. - ((nil) (org-latex--text-markup code 'code info)) - ;; Use minted package. - (minted - (let* ((org-lang (org-element-property :language inline-src-block)) - (mint-lang (or (cadr (assq (intern org-lang) - (plist-get info :latex-minted-langs))) - (downcase org-lang))) - (options (org-latex--make-option-string - (plist-get info :latex-minted-options)))) - (format "\\mintinline%s{%s}{%s}" - (if (string= options "") "" (format "[%s]" options)) - mint-lang - code))) - ;; Use listings package. - (otherwise - ;; Maybe translate language's name. - (let* ((org-lang (org-element-property :language inline-src-block)) - (lst-lang (or (cadr (assq (intern org-lang) - (plist-get info :latex-listings-langs))) - org-lang)) - (options (org-latex--make-option-string - (append (plist-get info :latex-listings-options) - `(("language" ,lst-lang)))))) - (concat (format "\\lstinline[%s]" options) - separator code separator)))))) - + (let ((code (org-element-property :value inline-src-block)) + (lang (org-element-property :language inline-src-block))) + (pcase (plist-get info :latex-listings) + ('nil (org-latex--text-markup code 'code info)) + ('minted (org-latex-inline-src-block--minted info code lang)) + (_ (org-latex-inline-src-block--listings info code lang))))) + +(defun org-latex-inline-src-block--minted (info code lang) + (let ((mint-lang (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase org-lang))) + (options (org-latex--make-option-string + (plist-get info :latex-minted-options)))) + (format "\\mintinline%s{%s}{%s}" + (if (string= options "") "" (format "[%s]" options)) + mint-lang + code))) + +(defun org-latex-inline-src-block--listings (info code lang) + (let* ((lst-lang (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + org-lang)) + (separator (org-latex--find-verb-separator code)) + (options (org-latex--make-option-string + (append (plist-get info :latex-listings-options) + `(("language" ,lst-lang)))))) + (concat (format "\\lstinline[%s]" options) + separator code separator))) ;;;; Inlinetask -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-ox-latex-More-versitile-option-construction.patch --] [-- Type: text/x-patch, Size: 4116 bytes --] From b322e67cc8b88826be26ee8ae155467aa764e743 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 4 May 2022 23:31:59 +0800 Subject: [PATCH 3/4] ox-latex: More versitile option construction * lisp/ox-latex.el (org-latex--make-option-string): Support a custom option seperator string. (org-latex--make-option-string, org-latex-minted-options, org-latex-listings-options): The first line of the docstrings for `org-latex-minted-options` and `org-latex-listings-options` describe the variables as "association lists", yet `org-latex--make-option-string` does not handle association lists and an example of two-value lists is provided. To make the behaviour match the docstring, `org-latex--make-option-string` is modified to work with either a list two-value lists or an association list, and the examples in `org-latex-minted-options` and `org-latex-listings-options` updated accordingly. --- lisp/ox-latex.el | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index ed66a51c0..6a29efcba 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -1006,12 +1006,16 @@ (defcustom org-latex-listings-options nil These options are supplied as a comma-separated list to the \\lstset command. Each element of the association list should be -a list containing two strings: the name of the option, and the -value. For example, +a list or cons cell containing two strings: the name of the +option, and the value. For example, (setq org-latex-listings-options \\='((\"basicstyle\" \"\\\\small\") (\"keywordstyle\" \"\\\\color{black}\\\\bfseries\\\\underbar\"))) + ; or + (setq org-latex-listings-options + \\='((\"basicstyle\" . \"\\\\small\") + (\"keywordstyle\" . \"\\\\color{black}\\\\bfseries\\\\underbar\"))) will typeset the code in a small size font with underlined, bold black keywords. @@ -1059,11 +1063,14 @@ (defcustom org-latex-minted-options nil These options are supplied within square brackets in \\begin{minted} environments. Each element of the alist should -be a list containing two strings: the name of the option, and the -value. For example, +be a list or cons cell containing two strings: the name of the +option, and the value. For example, (setq org-latex-minted-options \\='((\"bgcolor\" \"bg\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-minted-options + \\='((\"bgcolor\" . \"bg\") (\"frame\" . \"lines\"))) will result in source blocks being exported with @@ -1506,21 +1513,24 @@ (defun org-latex--find-verb-separator (s) when (not (string-match (regexp-quote (char-to-string c)) s)) return (char-to-string c)))) -(defun org-latex--make-option-string (options) +(defun org-latex--make-option-string (options &optional seperator) "Return a comma separated string of keywords and values. OPTIONS is an alist where the key is the options keyword as a string, and the value a list containing the keyword value, or nil." (mapconcat (lambda (pair) - (pcase-let ((`(,keyword ,value) pair)) - (concat keyword - (and (> (length value) 0) - (concat "=" - (if (string-match-p (rx (any "[]")) value) - (format "{%s}" value) - value)))))) - options - ",")) + (let ((keyword (car pair)) + (value (pcase (cdr pair) + ((pred stringp) (cdr pair)) + ((pred consp) (cadr pair))))) + (concat keyword + (when value + (concat "=" + (if (string-match-p (rx (any "[]")) value) + (format "{%s}" value) + value)))))) + options + (or seperator ","))) (defun org-latex--wrap-label (element output info) "Wrap label associated to ELEMENT around OUTPUT, if appropriate. -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-ox-latex-Introduce-engraved-code-highlighting.patch --] [-- Type: text/x-patch, Size: 15169 bytes --] From e0310e21e260a930e06d704ec8893ab1e75518aa Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 20:04:12 +0800 Subject: [PATCH 4/4] ox-latex: Introduce "engraved" code highlighting * lisp/ox-latex.el (org-latex-src-block, org-latex-src-block--engraved, org-latex-inline-src-block, org-latex-inline-src-block--engraved, org-latex-template, org-latex-listings): Make use of the engraved-faces package (available on ELPA) to provide an alternative LaTeX code highlighting backend which functions similarly to htmlize.el for HTML exports. (org-latex-engraved-preamble, org-latex-engraved-options): Introduce variables to construct the preamble for engraved code blocks. * lisp/ox-beamer.el (org-beamer-template): Modify to add engrave-faces preamble when applicable. --- lisp/ox-beamer.el | 9 ++ lisp/ox-latex.el | 235 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 241 insertions(+), 3 deletions(-) diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 6be73c91e..ca1aeafe4 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -857,6 +857,15 @@ (defun org-beamer-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template (org-latex--format-spec info)))) + ;; engrave-faces-latex preamble + (let ((engraved-p (eq org-latex-listings 'engraved)) + (src-p (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity)) + (fixedw-p + (org-element-map (plist-get info :parse-tree) + '(example-block fixed-width) #'identity))) + (when (or src-p fixedw-p) + (org-latex-generate-engraved-preamble info src-p))) ;; Document start. "\\begin{document}\n\n" ;; Title command. diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 6a29efcba..4cc82f6e7 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -37,6 +37,8 @@ (defvar org-latex-default-packages-alist) (defvar org-latex-packages-alist) (defvar orgtbl-exp-regexp) +(declare-function engrave-faces-latex-gen-preamble "ext:engrave-faces-latex") +(declare-function engrave-faces-latex-buffer "ext:engrave-faces-latex") \f ;;; Define Back-End @@ -125,6 +127,8 @@ (org-export-define-backend 'latex (:latex-default-quote-environment nil nil org-latex-default-quote-environment) (:latex-default-table-mode nil nil org-latex-default-table-mode) (:latex-diary-timestamp-format nil nil org-latex-diary-timestamp-format) + (:latex-engraved-options nil nil org-latex-engraved-options) + (:latex-engraved-preamble nil nil org-latex-engraved-preamble) (:latex-footnote-defined-format nil nil org-latex-footnote-defined-format) (:latex-footnote-separator nil nil org-latex-footnote-separator) (:latex-format-drawer-function nil nil org-latex-format-drawer-function) @@ -946,7 +950,24 @@ (defcustom org-latex-listings nil (add-to-list \\='org-latex-packages-alist \\='(\"\" \"listings\")) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"color\")) -Alternatively, +There are two fancier options for fontification. + +The first fancy alternative, + + (setq org-latex-listings \\='engraved) + +causes source code to be run through +`engrave-faces-latex-buffer', which generates colorings using +Emacs' font-lock information. This requires the engrave-faces +package (availible from ELPA), and the fvextra LaTeX package be +installed. + +The styling of the engraved result can customised with +`org-latex-engraved-preamble' and `org-latex-engraved-options'. +The default preamble also uses the tcolorbox LaTeX package in +addition to fvextra. + +The second fancy alternative, (setq org-latex-listings \\='minted) @@ -971,8 +992,9 @@ (defcustom org-latex-listings nil :type '(choice (const :tag "Use listings" t) (const :tag "Use minted" minted) + (const :tag "Use engrave-faces-latex" engraved) (const :tag "Export verbatim" nil)) - :safe (lambda (s) (memq s '(t nil minted)))) + :safe (lambda (s) (memq s '(t nil minted engraved)))) (defcustom org-latex-listings-langs '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp") @@ -1142,6 +1164,109 @@ (defcustom org-latex-custom-lang-environments nil :version "26.1" :package-version '(Org . "9.0")) +(defcustom org-latex-engraved-preamble + "\\usepackage{fvextra} + +[FVEXTRA-SETUP] + +\\renewcommand\\theFancyVerbLine{\\footnotesize\\color{black!40!white}\\arabic{FancyVerbLine}} + +\\providecolor{codebackground}{HTML}{f7f7f7} +\\providecolor{codeborder}{HTML}{f0f0f0} +\\providecolor{EFD}{HTML}{28292e} + +% TODO have code boxes keep line vertical alignment +\\usepackage[breakable,xparse]{tcolorbox} +\\DeclareTColorBox[]{Code}{o}% +{colback=codebackground, colframe=codeborder, + fontupper=\\footnotesize\\setlength{\\fboxsep}{0pt}, + colupper=EFD, + IfNoValueTF={#1}% + {boxsep=2pt, arc=2.5pt, outer arc=2.5pt, + boxrule=0.5pt, left=2pt}% + {boxsep=2.5pt, arc=0pt, outer arc=0pt, + boxrule=0pt, leftrule=1.5pt, left=0.5pt}, + right=2pt, top=1pt, bottom=0.5pt, + breakable}" + "Preamble content injected when using engrave-faces-latex for source blocks. +This is relevant when `org-latex-listings' is set to `engraved'. + +There is quite a lot of flexibility in what this preamble can be, as long as it: +- Loads the fvextra package. +- Defines a \"Code\" environment (note the capital C), which can be + later used to wrap \"Verbatim\" environments (provided by fvextra). + +A macro-like placeholder is used to set fvextra's defaults according to +`org-latex-engraved-options': + + [FVEXTRA-SETUP]" + :group 'org-export-latex + :type 'string + :package-version '(Org . "9.6")) + +(defcustom org-latex-engraved-options + '(("commandchars" . "\\\\\\{\\}") + ("highlightcolor" . "white!95!black!80!blue") + ("breaklines" . "true") + ("breaksymbol" . "\\color{white!60!black}\\tiny\\ensuremath{\\hookrightarrow}")) + "Association list of options for the latex fvextra package when engraving code. + +These options are set using \\fvset{...} in the preamble of the +LaTeX export. Each element of the alist should be a list or cons +cell containing two strings: the name of the option, and the +value. For example, + + (setq org-latex-engraved-options + \\='((\"bgcolor\" \"bg\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-engraved-options + \\='((\"bgcolor\" . \"bg\") (\"frame\" . \"lines\"))) + +will result in the following LaTeX in the preamble + +\\fvset{% + bgcolor=bg, + frame=lines} + +This will affect all fvextra environments. Note that the same +options will be applied to all blocks. If you need +block-specific options, you may use the following syntax: + + #+ATTR_LATEX: :options key1=value1,key2=value2 + #+BEGIN_SRC <LANG> + ... + #+END_SRC") + +(defun org-latex-generate-engraved-preamble (info syntax-colours-p) + (let* ((engraved-options + (plist-get info :latex-engraved-options)) + (engraved-preamble-template + (plist-get info :latex-engraved-preamble)) + (engraved-preamble + (if (string-match "^[ \t]*\\[FVEXTRA-SETUP\\][ \t]*\n?" + org-latex-engraved-preamble) + (replace-match + (concat + "\\fvset{%\n " + (org-latex--make-option-string engraved-options ",\n ") + "}\n") + t t + engraved-preamble-template) + engraved-preamble-template))) + (if syntax-colours-p + (concat + "\n% Setup for code blocks [1/2]\n\n" + engraved-preamble + "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n" + (if (require 'engrave-faces-latex nil t) + (engrave-faces-latex-gen-preamble) + (message "Cannot engrave source blocks. Consider installing `engrave-faces'.") + "% WARNING syntax highlighting unavailible as engrave-faces-latex was missing.\n") + "\n") + (concat + "\n% Setup for code blocks\n\n" + engraved-preamble + "\n")))) ;;;; Compilation @@ -1756,6 +1881,15 @@ (defun org-latex-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template spec))) + ;; engrave-faces-latex preamble + (let ((engraved-p (eq org-latex-listings 'engraved)) + (src-p (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity)) + (fixedw-p + (org-element-map (plist-get info :parse-tree) + '(example-block fixed-width) #'identity))) + (when (or src-p fixedw-p) + (org-latex-generate-engraved-preamble info src-p))) ;; Document start. "\\begin{document}\n\n" ;; Title command. @@ -2142,12 +2276,13 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) (pcase (plist-get info :latex-listings) ('nil (org-latex--text-markup code 'code info)) ('minted (org-latex-inline-src-block--minted info code lang)) + ('engraved (org-latex-inline-src-block--engraved info code lang)) (_ (org-latex-inline-src-block--listings info code lang))))) (defun org-latex-inline-src-block--minted (info code lang) (let ((mint-lang (or (cadr (assq (intern lang) (plist-get info :latex-minted-langs))) - (downcase org-lang))) + (downcase lang))) (options (org-latex--make-option-string (plist-get info :latex-minted-options)))) (format "\\mintinline%s{%s}{%s}" @@ -2155,6 +2290,23 @@ (defun org-latex-inline-src-block--minted (info code lang) mint-lang code))) +(defun org-latex-inline-src-block--engraved (info code lang) + (if (require 'engrave-faces-latex nil t) + (let (engraved-buffer engraved-code) + (setq engraved-buffer + (with-temp-buffer + (insert code) + (funcall (org-src-get-lang-mode lang)) + (engrave-faces-latex-buffer))) + (setq engraved-code + (with-current-buffer engraved-buffer + (buffer-string))) + (kill-buffer engraved-buffer) + (format "\\Verb{%s}" + engraved-code)) + (message "Cannot engrave inline src block, `engrave-faces-latex' is unavailible.") + (insert (org-latex--text-markup code 'code info)))) + (defun org-latex-inline-src-block--listings (info code lang) (let* ((lst-lang (or (cadr (assq (intern lang) (plist-get info :latex-listings-langs))) @@ -3013,6 +3165,9 @@ (defun org-latex-src-block (src-block _contents info) num-start retain-labels attributes float custom-env)) ((eq listings 'minted) (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) + ((eq listings 'engraved) + (org-latex-src-block--engraved src-block info lang caption caption-above-p label num-start retain-labels attributes float)) (t (org-latex-src-block--listings src-block info lang caption caption-above-p label @@ -3129,6 +3284,80 @@ (defun org-latex-src-block--minted ;; Return value. (format float-env body))) +(defun org-latex-src-block--engraved + (src-block info lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using engrave-faces-latex. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (if (require 'engrave-faces-latex nil t) + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-engraved-options)) + (content-buffer + (with-temp-buffer + (insert + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))) + (funcall (org-src-get-lang-mode lang)) + (engrave-faces-latex-buffer))) + (content + (with-current-buffer content-buffer + (buffer-string))) + (body + (format + "\\begin{Code}\n\\begin{Verbatim}[%s]\n%s\\end{Verbatim}\n\\end{Code}" + ;; Options. + (concat + (org-latex--make-option-string + (append + (when (and num-start (not (assoc "linenos" options))) + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (list local-options)))))) + content))) + (kill-buffer content-buffer) + ;; Return value. + (format float-env body)) + (message "Cannot engrave src block, `engrave-faces-latex' is unavailible.") + (insert (org-latex--text-markup code 'code info)))) + (defun org-latex-src-block--listings (src-block info lang caption caption-above-p label num-start retain-labels attributes float) -- 2.35.3 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-04 15:59 [PATCH] New LaTeX code export option: engraved Timothy @ 2022-05-05 7:52 ` Daniel Fleischer 2022-05-05 16:09 ` Timothy 2022-05-05 7:54 ` Daniel Fleischer ` (2 subsequent siblings) 3 siblings, 1 reply; 27+ messages in thread From: Daniel Fleischer @ 2022-05-05 7:52 UTC (permalink / raw) To: Timothy; +Cc: emacs-orgmode, Nicolas Goaziou Timothy [2022-05-04 Wed 23:59] wrote: > I’ve been fairly busy as of late (hence my recent silence on this ML), however I have a patchset that’s been in the > works for a while that I’ve finally polished up. Hi Timothy, thank you very much for your work! Let me learn a bit about the different code highlighting options in order to understand what you offer. Best, -- Daniel Fleischer ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-05 7:52 ` Daniel Fleischer @ 2022-05-05 16:09 ` Timothy 2022-05-06 2:35 ` Ihor Radchenko 0 siblings, 1 reply; 27+ messages in thread From: Timothy @ 2022-05-05 16:09 UTC (permalink / raw) To: Daniel Fleischer; +Cc: emacs-orgmode, Nicolas Goaziou [-- Attachment #1: Type: text/plain, Size: 336 bytes --] Hi Daniel, > Hi Timothy, thank you very much for your work! Thanks for the kind words 🙂 > Let me learn a bit about the different code highlighting options in > order to understand what you offer. Sure. If it’s any help, here’s a comparison example I whipped up: <https://0x0.st/oAdn.png> All the best, Timothy ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-05 16:09 ` Timothy @ 2022-05-06 2:35 ` Ihor Radchenko 2022-05-06 11:23 ` Timothy 0 siblings, 1 reply; 27+ messages in thread From: Ihor Radchenko @ 2022-05-06 2:35 UTC (permalink / raw) To: Timothy; +Cc: Daniel Fleischer, emacs-orgmode, Nicolas Goaziou Timothy <tecosaur@gmail.com> writes: >> Let me learn a bit about the different code highlighting options in >> order to understand what you offer. > > Sure. If it’s any help, here’s a comparison example I whipped up: > <https://0x0.st/oAdn.png> Timothy, could you please not use 0x0 to share not-so-large images? 0x0 deletes uploaded files within ~1year time and this link will no longer be valid if someone tries to read this discussion years later. Also, this illustration makes me wonder if engrave-faces can provide a color scheme that is mimicking minted. Generally, easy customisation of highlight schemes could be useful. On per-src-block basis or even on per-language basis if document contains course blocks with different programming languages. Best, Ihor ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-06 2:35 ` Ihor Radchenko @ 2022-05-06 11:23 ` Timothy 0 siblings, 0 replies; 27+ messages in thread From: Timothy @ 2022-05-06 11:23 UTC (permalink / raw) To: Ihor Radchenko; +Cc: Daniel Fleischer, emacs-orgmode, Nicolas Goaziou [-- Attachment #1: Type: text/plain, Size: 1407 bytes --] Hi Ihor, >> Sure. If it’s any help, here’s a comparison example I whipped up: >> <https://0x0.st/oAdn.png> > > Timothy, could you please not use 0x0 to share not-so-large images? 0x0 > deletes uploaded files within ~1year time and this link will no longer > be valid if someone tries to read this discussion years later. I forget if org-msg handles image links well (I recall some issue in the past). Let’s do a little test: <file:/tmp/ox-latex-src-fontification-comparison.png> > Also, this illustration makes me wonder if engrave-faces can provide a > color scheme that is mimicking minted. One could certainly create `engrave-faces-preset-styles' presets which mimic certain minted colour schemes. > Generally, easy customisation of highlight schemes could be useful. I agree. Is this not already the case though? Manually modifying `engrave-faces-preset-styles' or calling `engrave-faces-generate-preset' seems pretty easy to me, the only thing missing is the ability to generate a preset from a theme not loaded, which I suspect won’t be easy to do. > On per-src-block basis or even on per-language basis if document contains > course blocks with different programming languages. I can’t say I really see the point in this myself. It would certainly be non-trivial to add, but could be added latter if there’s demand for it. All the best, Timothy [-- Attachment #2: ox-latex-src-fontification-comparison.png --] [-- Type: image/png, Size: 476505 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-04 15:59 [PATCH] New LaTeX code export option: engraved Timothy 2022-05-05 7:52 ` Daniel Fleischer @ 2022-05-05 7:54 ` Daniel Fleischer 2022-05-05 8:48 ` Ihor Radchenko 2022-05-09 19:19 ` Sébastien Miquel 3 siblings, 0 replies; 27+ messages in thread From: Daniel Fleischer @ 2022-05-05 7:54 UTC (permalink / raw) To: Timothy; +Cc: emacs-orgmode, Nicolas Goaziou Timothy [2022-05-04 Wed 23:59] wrote: > I’ve been fairly busy as of late (hence my recent silence on this ML), however I have a patchset that’s been in the > works for a while that I’ve finally polished up. Hi Timothy, thank you very much for your work! Let me learn a bit about the different code highlighting options in order to understand what you offer. Best, -- Daniel Fleischer ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-04 15:59 [PATCH] New LaTeX code export option: engraved Timothy 2022-05-05 7:52 ` Daniel Fleischer 2022-05-05 7:54 ` Daniel Fleischer @ 2022-05-05 8:48 ` Ihor Radchenko 2022-05-05 15:17 ` Timothy 2022-05-09 19:19 ` Sébastien Miquel 3 siblings, 1 reply; 27+ messages in thread From: Ihor Radchenko @ 2022-05-05 8:48 UTC (permalink / raw) To: Timothy; +Cc: emacs-orgmode, Daniel Fleischer, Nicolas Goaziou [-- Attachment #1: Type: text/plain, Size: 1338 bytes --] Timothy <tecosaur@gmail.com> writes: > This patchset accomplishes two things: > 1. It refactors the overly large `org-latex-src-block' function, and makes a few > other improvements to pre-existing code > 2. It adds a new option for exporting code, named (you guessed it!) “engraved” > > What is this new option, and why do we want it? > > About a year ago I started work on a package that generalises the functionality > of `htmlize.el', termed `engrave-faces' > (<https://elpa.gnu.org/packages/engrave-faces.html>). It provides the ability to > extract font-lock information and export it to a number of formats: html, ansi, > and (crucially) LaTeX! Since the LaTeX export is built on the `fvextra' (LaTeX) > package (like pygments), the vast majority of the Minted options you’re used to > just carry over. > > This allows for a result that is, I think, straight up better than all the > pre-existing options. For starters, you can now apply syntax highlighting to any > language you have a major mode for. Thanks! Implementing fontification using Emacs capabilities is certainly a step in the right direction. LaTeX support for fontification has always been tricky. Some comments: - I tried to test your patch, and it only works partially. There is some stray text caused by LaTeX errors: [-- Attachment #2: test.org --] [-- Type: application/vnd.lotus-organizer, Size: 396 bytes --] #+STARTUP: indent Enable soft indent mode **** Header Level 4 The text belonging to level-4 header *************** Inline Task Text belonging to inline task *************** END #+caption: This is caption #+begin_src emacs-lisp (message "Hello world and very very very long line afterwards lakjsdlk sjsaldjkjsa ldjalskdjalsjdlalds jalskdjalsjdlas kdjalsdjlsjdals djasdjasljdasljdslj") #+end_src [-- Attachment #3: test.pdf --] [-- Type: application/pdf, Size: 93821 bytes --] [-- Attachment #4: Type: text/plain, Size: 2329 bytes --] - You did not add a NEWS entry and did not update the manual in your patch. - There are many compiler warnings emitted when compiling Org with your patch > +(defun org-latex-inline-src-block--minted (info code lang) > + (let ((mint-lang (or (cadr (assq (intern lang) > + > +(defun org-latex-inline-src-block--listings (info code lang) > + (let* ((lst-lang (or (cadr (assq (intern lang) The docstrings are missing in the above. > -Alternatively, > +There are two fancier options for fontification. > + > +The first fancy alternative, I am not sure why, but the word fancy feels slightly annoying here. > + > +The styling of the engraved result can customised with > +`org-latex-engraved-preamble' and `org-latex-engraved-options'. > +The default preamble also uses the tcolorbox LaTeX package in > +addition to fvextra. Since engraved is not entirely relying on LaTeX options, a lot of customisation is not mentioned in this docstring. AFAIU, color customisation is only possible by changing defcustoms from engrave-faces package. Another related note is what is going to happen in beamer export with dark background. The default face mapping in engrave-faces is using some kind of light theme, which may lose all the contrast on not-light background. > +\\renewcommand\\theFancyVerbLine{\\footnotesize\\color{black!40!white}\\arabic{FancyVerbLine}} > + > +\\providecolor{codebackground}{HTML}{f7f7f7} > +\\providecolor{codeborder}{HTML}{f0f0f0} > +\\providecolor{EFD}{HTML}{28292e} > +(defcustom org-latex-engraved-options > + '(("commandchars" . "\\\\\\{\\}") > + ("highlightcolor" . "white!95!black!80!blue") > + ("breaklines" . "true") > + ("breaksymbol" . "\\color{white!60!black}\\tiny\\ensuremath{\\hookrightarrow}")) > + "Association list of options for the latex fvextra package when engraving code. It feels that codebackground, codeborder, and EFD should be customizable by org-latex-engraved-options. > +(defun org-latex-generate-engraved-preamble (info syntax-colours-p) Docstring? > +(defun org-latex-inline-src-block--engraved (info code lang) > + (if (require 'engrave-faces-latex nil t) > ... > + (message "Cannot engrave inline src block, `engrave-faces-latex' is unavailible.") > + (insert (org-latex--text-markup code 'code info)))) Why message instead of error? Best, Ihor ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-05 8:48 ` Ihor Radchenko @ 2022-05-05 15:17 ` Timothy 2022-05-05 16:13 ` Timothy 2022-05-05 16:48 ` [PATCH] " Max Nikulin 0 siblings, 2 replies; 27+ messages in thread From: Timothy @ 2022-05-05 15:17 UTC (permalink / raw) To: Ihor Radchenko; +Cc: emacs-orgmode, Daniel Fleischer, Nicolas Goaziou [-- Attachment #1: Type: text/plain, Size: 2879 bytes --] Hi Ihor, > Thanks! > Implementing fontification using Emacs capabilities is certainly a step > in the right direction. LaTeX support for fontification has always been > tricky. I’m glad to hear you’re of a similar mind to me with this. > - I tried to test your patch, and it only works partially. There is some > stray text caused by LaTeX errors: > > [2. application/vnd.lotus-organizer; test.org]… > [3. application/pdf; test.pdf]… Ah. I thought that hyperref loaded xcolor, but it seems my assumption was incorrect. I’ve added `\usepackage{xcolor}' to the default `org-latex-engraved-preamble', but maybe I should ask people to modify `org-latex-packages-alist'. I’m not sure. > - You did not add a NEWS entry and did not update the manual in your patch. I’m waiting till the functional content of these packages is settled/accepted, and then I’ll write NEWS and manual entries. > - There are many compiler warnings emitted when compiling Org with your patch Oops, I keep on forgetting to check byte compilation. These should all be fixed now. > The docstrings are missing in the above. Docstrings have been added. > I am not sure why, but the word fancy feels slightly annoying here. Docsting rewritten. > Since engraved is not entirely relying on LaTeX options, a lot of > customisation is not mentioned in this docstring. AFAIU, color > customisation is only possible by changing defcustoms from engrave-faces > package. > > Another related note is what is going to happen in beamer export with > dark background. The default face mapping in engrave-faces is using some > kind of light theme, which may lose all the contrast on not-light > background. Modifying the style of engraved-faces-latex’s output is indeed done by customising a engraved-faces variable. I don’t think we should attempt to do anything further with this within Org. To elaborate a bit, the generated LaTeX uses the styling information given in `engrave-faces-preset-styles'. Changing this to use the current Emacs theme is as simple as `(setq engrave-faces-preset-styles (engrave-faces-generate-preset))'. > It feels that codebackground, codeborder, and EFD should be customizable > by org-latex-engraved-options. Hmm. I don’t think so. They are entirely self-contained within the preamble variable. Should there be a nice existing `org-latex-user-colors' variable or such, it would make a lot of sense to shove this there, but since no such variable exists I’m not sure we can really do much better than just asking users to modify `org-latex-engraved-preamble'. > Docstring? Added. >> + (message “Cannot engrave inline src block, `engrave-faces-latex’ is unavailible.”) > > Why message instead of error? User errors are now thrown. Thanks for the feedback! Timothy [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-ox-latex-Refactor-org-latex-src-block.patch --] [-- Type: text/x-patch, Size: 15942 bytes --] From d231437e2c9f96bf70520d9ddda810a95667fcdd Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 14:35:34 +0800 Subject: [PATCH 1/4] ox-latex: Refactor `org-latex-src-block' * lisp/ox-latex.el (org-latex-src-block): Extract the per-format logic from `org-latex-src-block' into new dedicated functions: + `org-latex-src-block--verbatim' + `org-latex-src-block--custom' + `org-latex-src-block--minted' + `org-latex-src-block--listings' This makes `org-latex-src-block' much less monolithic, taking it from 175 lines to 30, and I find also makes it easier to understand. --- lisp/ox-latex.el | 339 ++++++++++++++++++++++++++--------------------- 1 file changed, 185 insertions(+), 154 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 841ad48bc..c2f728a1c 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2997,164 +2997,195 @@ (defun org-latex-src-block (src-block _contents info) (float (plist-get attributes :float)) (listings (plist-get info :latex-listings))) (cond - ;; Case 1. No source fontification. ((or (not lang) (not listings)) - (let ((caption-str (org-latex--caption/label-string src-block info)) - (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" - (org-export-format-code-default src-block info)))) - (cond ((string= "multicolumn" float) - (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" - (plist-get info :latex-default-figure-position) - (if caption-above-p caption-str "") - verbatim - (if caption-above-p "" caption-str))) - (caption (concat - (if caption-above-p caption-str "") - verbatim - (if caption-above-p "" (concat "\n" caption-str)))) - (t verbatim)))) - ;; Case 2. Custom environment. + (org-latex-src-block--verbatim src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) (custom-env - (let ((caption-str (org-latex--caption/label-string src-block info)) - (formatted-src (org-export-format-code-default src-block info))) - (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) - (format "\\begin{%s}\n%s\\end{%s}\n" - custom-env - (concat (and caption-above-p caption-str) - formatted-src - (and (not caption-above-p) caption-str)) - custom-env) - (format-spec custom-env - `((?s . ,formatted-src) - (?c . ,caption) - (?f . ,float) - (?l . ,(org-latex--label src-block info)) - (?o . ,(or (plist-get attributes :options) ""))))))) - ;; Case 3. Use minted package. + (org-latex-src-block--custom src-block info lang caption caption-above-p label + num-start retain-labels attributes float custom-env)) ((eq listings 'minted) - (let* ((caption-str (org-latex--caption/label-string src-block info)) - (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) - (plist-get info :latex-default-figure-position))) - (float-env - (cond - ((string= "multicolumn" float) - (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - (caption - (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - ((string= "t" float) - (concat (format "\\begin{listing}[%s]\n" - placement) - "%s\n\\end{listing}")) - (t "%s"))) - (options (plist-get info :latex-minted-options)) - (body - (format - "\\begin{minted}[%s]{%s}\n%s\\end{minted}" - ;; Options. - (concat - (org-latex--make-option-string - (if (or (not num-start) (assoc "linenos" options)) - options - (append - `(("linenos") - ("firstnumber" ,(number-to-string (1+ num-start)))) - options))) - (let ((local-options (plist-get attributes :options))) - (and local-options (concat "," local-options)))) - ;; Language. - (or (cadr (assq (intern lang) - (plist-get info :latex-minted-langs))) - (downcase lang)) - ;; Source code. - (let* ((code-info (org-export-unravel-code src-block)) - (max-width - (apply 'max - (mapcar 'length - (org-split-string (car code-info) - "\n"))))) - (org-export-format-code - (car code-info) - (lambda (loc _num ref) - (concat - loc - (when ref - ;; Ensure references are flushed to the right, - ;; separated with 6 spaces from the widest line - ;; of code. - (concat (make-string (+ (- max-width (length loc)) 6) - ?\s) - (format "(%s)" ref))))) - nil (and retain-labels (cdr code-info))))))) - ;; Return value. - (format float-env body))) - ;; Case 4. Use listings package. + (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) (t - (let ((lst-lang - (or (cadr (assq (intern lang) - (plist-get info :latex-listings-langs))) - lang)) - (caption-str - (when caption - (let ((main (org-export-get-caption src-block)) - (secondary (org-export-get-caption src-block t))) - (if (not secondary) - (format "{%s}" (org-export-data main info)) - (format "{[%s]%s}" - (org-export-data secondary info) - (org-export-data main info)))))) - (lst-opt (plist-get info :latex-listings-options))) - (concat - ;; Options. - (format - "\\lstset{%s}\n" - (concat - (org-latex--make-option-string - (append - lst-opt - (cond - ((and (not float) (plist-member attributes :float)) nil) - ((string= "multicolumn" float) '(("float" "*"))) - ((and float (not (assoc "float" lst-opt))) - `(("float" ,(plist-get info :latex-default-figure-position))))) - `(("language" ,lst-lang)) - (if label - `(("label" ,(org-latex--label src-block info))) - '(("label" " "))) - (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) - `(("captionpos" ,(if caption-above-p "t" "b"))) - (cond ((assoc "numbers" lst-opt) nil) - ((not num-start) '(("numbers" "none"))) - (t `(("firstnumber" ,(number-to-string (1+ num-start))) - ("numbers" "left")))))) - (let ((local-options (plist-get attributes :options))) - (and local-options (concat "," local-options))))) - ;; Source code. - (format - "\\begin{lstlisting}\n%s\\end{lstlisting}" - (let* ((code-info (org-export-unravel-code src-block)) - (max-width - (apply 'max - (mapcar 'length - (org-split-string (car code-info) "\n"))))) - (org-export-format-code - (car code-info) - (lambda (loc _num ref) - (concat - loc - (when ref - ;; Ensure references are flushed to the right, - ;; separated with 6 spaces from the widest line of - ;; code - (concat (make-string (+ (- max-width (length loc)) 6) ?\s) - (format "(%s)" ref))))) - nil (and retain-labels (cdr code-info)))))))))))) - + (org-latex-src-block--listings src-block info lang caption caption-above-p label + num-start retain-labels attributes float)))))) + +(defun org-latex-src-block--verbatim + (src-block info _lang caption caption-above-p _label + _num-start _retain-labels _attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using verbatim. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((caption-str (org-latex--caption/label-string src-block info)) + (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" + (org-export-format-code-default src-block info)))) + (cond ((string= "multicolumn" float) + (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" + (plist-get info :latex-default-figure-position) + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" caption-str))) + (caption (concat + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" (concat "\n" caption-str)))) + (t verbatim)))) + +(defun org-latex-src-block--custom + (src-block info _lang caption caption-above-p _label + _num-start _retain-labels attributes float custom-env) + "Transcode a SRC-BLOCK element from Org to LaTeX, using a custom environment. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((caption-str (org-latex--caption/label-string src-block info)) + (formatted-src (org-export-format-code-default src-block info))) + (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) + (format "\\begin{%s}\n%s\\end{%s}\n" + custom-env + (concat (and caption-above-p caption-str) + formatted-src + (and (not caption-above-p) caption-str)) + custom-env) + (format-spec custom-env + `((?s . ,formatted-src) + (?c . ,caption) + (?f . ,float) + (?l . ,(org-latex--label src-block info)) + (?o . ,(or (plist-get attributes :options) ""))))))) + +(defun org-latex-src-block--minted + (src-block info lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using minted. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-minted-options)) + (body + (format + "\\begin{minted}[%s]{%s}\n%s\\end{minted}" + ;; Options. + (concat + (org-latex--make-option-string + (if (or (not num-start) (assoc "linenos" options)) + options + (append + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start)))) + options))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options)))) + ;; Language. + (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase lang)) + ;; Source code. + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))))) + ;; Return value. + (format float-env body))) + +(defun org-latex-src-block--listings + (src-block info lang caption caption-above-p label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using listings. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((lst-lang + (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + lang)) + (caption-str + (when caption + (let ((main (org-export-get-caption src-block)) + (secondary (org-export-get-caption src-block t))) + (if (not secondary) + (format "{%s}" (org-export-data main info)) + (format "{[%s]%s}" + (org-export-data secondary info) + (org-export-data main info)))))) + (lst-opt (plist-get info :latex-listings-options))) + (concat + ;; Options. + (format + "\\lstset{%s}\n" + (concat + (org-latex--make-option-string + (append + lst-opt + (cond + ((and (not float) (plist-member attributes :float)) nil) + ((string= "multicolumn" float) '(("float" "*"))) + ((and float (not (assoc "float" lst-opt))) + `(("float" ,(plist-get info :latex-default-figure-position))))) + `(("language" ,lst-lang)) + (if label + `(("label" ,(org-latex--label src-block info))) + '(("label" " "))) + (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) + `(("captionpos" ,(if caption-above-p "t" "b"))) + (cond ((assoc "numbers" lst-opt) nil) + ((not num-start) '(("numbers" "none"))) + (t `(("firstnumber" ,(number-to-string (1+ num-start))) + ("numbers" "left")))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options))))) + ;; Source code. + (format + "\\begin{lstlisting}\n%s\\end{lstlisting}" + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line of + ;; code + (concat (make-string (+ (- max-width (length loc)) 6) ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info)))))))) ;;;; Statistics Cookie -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-ox-latex-Refactor-org-latex-inline-src-block.patch --] [-- Type: text/x-patch, Size: 4020 bytes --] From ea5d116b06326be46e3053e6ded26d5b8b0638d9 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 4 May 2022 18:53:10 +0800 Subject: [PATCH 2/4] ox-latex: Refactor `org-latex-inline-src-block' * lisp/ox-latex.el (org-latex-inline-src-block, org-latex-inline-src-block--minted, org-latex-inline-src-block--listings): Extract the minted and listings specific logic out of `org-latex-inline-src-block` into the new functions `org-latex-inline-src-block--minted` and `org-latex-inline-src-block--listings`. --- lisp/ox-latex.el | 62 +++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index c2f728a1c..2b732cf16 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2127,36 +2127,38 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) "Transcode an INLINE-SRC-BLOCK element from Org to LaTeX. CONTENTS holds the contents of the item. INFO is a plist holding contextual information." - (let* ((code (org-element-property :value inline-src-block)) - (separator (org-latex--find-verb-separator code))) - (cl-case (plist-get info :latex-listings) - ;; Do not use a special package: transcode it verbatim, as code. - ((nil) (org-latex--text-markup code 'code info)) - ;; Use minted package. - (minted - (let* ((org-lang (org-element-property :language inline-src-block)) - (mint-lang (or (cadr (assq (intern org-lang) - (plist-get info :latex-minted-langs))) - (downcase org-lang))) - (options (org-latex--make-option-string - (plist-get info :latex-minted-options)))) - (format "\\mintinline%s{%s}{%s}" - (if (string= options "") "" (format "[%s]" options)) - mint-lang - code))) - ;; Use listings package. - (otherwise - ;; Maybe translate language's name. - (let* ((org-lang (org-element-property :language inline-src-block)) - (lst-lang (or (cadr (assq (intern org-lang) - (plist-get info :latex-listings-langs))) - org-lang)) - (options (org-latex--make-option-string - (append (plist-get info :latex-listings-options) - `(("language" ,lst-lang)))))) - (concat (format "\\lstinline[%s]" options) - separator code separator)))))) - + (let ((code (org-element-property :value inline-src-block)) + (lang (org-element-property :language inline-src-block))) + (pcase (plist-get info :latex-listings) + ('nil (org-latex--text-markup code 'code info)) + ('minted (org-latex-inline-src-block--minted info code lang)) + (_ (org-latex-inline-src-block--listings info code lang))))) + +(defun org-latex-inline-src-block--minted (info code lang) + "Transcode an inline src block's content from Org to LaTeX, using minted. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (let ((mint-lang (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase org-lang))) + (options (org-latex--make-option-string + (plist-get info :latex-minted-options)))) + (format "\\mintinline%s{%s}{%s}" + (if (string= options "") "" (format "[%s]" options)) + mint-lang + code))) + +(defun org-latex-inline-src-block--listings (info code lang) + "Transcode an inline src block's content from Org to LaTeX, using lstlistings. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (let* ((lst-lang (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + lang)) + (separator (org-latex--find-verb-separator code)) + (options (org-latex--make-option-string + (append (plist-get info :latex-listings-options) + `(("language" ,lst-lang)))))) + (concat (format "\\lstinline[%s]" options) + separator code separator))) ;;;; Inlinetask -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-ox-latex-More-versitile-option-construction.patch --] [-- Type: text/x-patch, Size: 4116 bytes --] From aa0a9dafab7a7246e2855a2257d4c156eb48752c Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 4 May 2022 23:31:59 +0800 Subject: [PATCH 3/4] ox-latex: More versitile option construction * lisp/ox-latex.el (org-latex--make-option-string): Support a custom option seperator string. (org-latex--make-option-string, org-latex-minted-options, org-latex-listings-options): The first line of the docstrings for `org-latex-minted-options` and `org-latex-listings-options` describe the variables as "association lists", yet `org-latex--make-option-string` does not handle association lists and an example of two-value lists is provided. To make the behaviour match the docstring, `org-latex--make-option-string` is modified to work with either a list two-value lists or an association list, and the examples in `org-latex-minted-options` and `org-latex-listings-options` updated accordingly. --- lisp/ox-latex.el | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 2b732cf16..4181db175 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -1006,12 +1006,16 @@ (defcustom org-latex-listings-options nil These options are supplied as a comma-separated list to the \\lstset command. Each element of the association list should be -a list containing two strings: the name of the option, and the -value. For example, +a list or cons cell containing two strings: the name of the +option, and the value. For example, (setq org-latex-listings-options \\='((\"basicstyle\" \"\\\\small\") (\"keywordstyle\" \"\\\\color{black}\\\\bfseries\\\\underbar\"))) + ; or + (setq org-latex-listings-options + \\='((\"basicstyle\" . \"\\\\small\") + (\"keywordstyle\" . \"\\\\color{black}\\\\bfseries\\\\underbar\"))) will typeset the code in a small size font with underlined, bold black keywords. @@ -1059,11 +1063,14 @@ (defcustom org-latex-minted-options nil These options are supplied within square brackets in \\begin{minted} environments. Each element of the alist should -be a list containing two strings: the name of the option, and the -value. For example, +be a list or cons cell containing two strings: the name of the +option, and the value. For example, (setq org-latex-minted-options \\='((\"bgcolor\" \"bg\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-minted-options + \\='((\"bgcolor\" . \"bg\") (\"frame\" . \"lines\"))) will result in source blocks being exported with @@ -1506,21 +1513,24 @@ (defun org-latex--find-verb-separator (s) when (not (string-match (regexp-quote (char-to-string c)) s)) return (char-to-string c)))) -(defun org-latex--make-option-string (options) +(defun org-latex--make-option-string (options &optional seperator) "Return a comma separated string of keywords and values. OPTIONS is an alist where the key is the options keyword as a string, and the value a list containing the keyword value, or nil." (mapconcat (lambda (pair) - (pcase-let ((`(,keyword ,value) pair)) - (concat keyword - (and (> (length value) 0) - (concat "=" - (if (string-match-p (rx (any "[]")) value) - (format "{%s}" value) - value)))))) - options - ",")) + (let ((keyword (car pair)) + (value (pcase (cdr pair) + ((pred stringp) (cdr pair)) + ((pred consp) (cadr pair))))) + (concat keyword + (when value + (concat "=" + (if (string-match-p (rx (any "[]")) value) + (format "{%s}" value) + value)))))) + options + (or seperator ","))) (defun org-latex--wrap-label (element output info) "Wrap label associated to ELEMENT around OUTPUT, if appropriate. -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-ox-latex-Introduce-engraved-code-highlighting.patch --] [-- Type: text/x-patch, Size: 17464 bytes --] From 90849f3986cc709c1d01ec9f204a7eb8b940cd27 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 20:04:12 +0800 Subject: [PATCH 4/4] ox-latex: Introduce "engraved" code highlighting * lisp/ox-latex.el (org-latex-src-block, org-latex-src-block--engraved, org-latex-inline-src-block, org-latex-inline-src-block--engraved, org-latex-template, org-latex-listings): Make use of the engraved-faces package (available on ELPA) to provide an alternative LaTeX code highlighting backend which functions similarly to htmlize.el for HTML exports. (org-latex-engraved-preamble, org-latex-engraved-options): Introduce variables to construct the preamble for engraved code blocks. * lisp/ox-beamer.el (org-beamer-template): Modify to add engrave-faces preamble when applicable. --- lisp/ox-beamer.el | 9 ++ lisp/ox-latex.el | 273 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 272 insertions(+), 10 deletions(-) diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 6be73c91e..73bd95539 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -857,6 +857,15 @@ (defun org-beamer-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template (org-latex--format-spec info)))) + ;; engrave-faces-latex preamble + (when (eq org-latex-listings 'engraved) + (let ((src-p (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity)) + (fixedw-p + (org-element-map (plist-get info :parse-tree) + '(example-block fixed-width) #'identity))) + (when (or src-p fixedw-p) + (org-latex-generate-engraved-preamble info src-p)))) ;; Document start. "\\begin{document}\n\n" ;; Title command. diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 4181db175..831509a26 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -37,6 +37,8 @@ (defvar org-latex-default-packages-alist) (defvar org-latex-packages-alist) (defvar orgtbl-exp-regexp) +(declare-function engrave-faces-latex-gen-preamble "ext:engrave-faces-latex") +(declare-function engrave-faces-latex-buffer "ext:engrave-faces-latex") \f ;;; Define Back-End @@ -125,6 +127,8 @@ (org-export-define-backend 'latex (:latex-default-quote-environment nil nil org-latex-default-quote-environment) (:latex-default-table-mode nil nil org-latex-default-table-mode) (:latex-diary-timestamp-format nil nil org-latex-diary-timestamp-format) + (:latex-engraved-options nil nil org-latex-engraved-options) + (:latex-engraved-preamble nil nil org-latex-engraved-preamble) (:latex-footnote-defined-format nil nil org-latex-footnote-defined-format) (:latex-footnote-separator nil nil org-latex-footnote-separator) (:latex-format-drawer-function nil nil org-latex-format-drawer-function) @@ -937,22 +941,48 @@ (defcustom org-latex-listings nil "Non-nil means export source code using the listings package. This package will fontify source code, possibly even with color. -If you want to use this, you also need to make LaTeX use the -listings package, and if you want to have color, the color -package. Just add these to `org-latex-packages-alist', for -example using customize, or with something like: +There are four implementations of this functionality you may +choose from (ordered from least to most capable): +1. Verbatim (nil) +2. Listings (t) +3. Minted (minted) +4. Engraved (engraved) + +The first two options provide basic syntax +highlighting (listings), or none at all (verbatim). + +When using listings, you also need to make use of the LaTeX +\"listings\" package. The \"color\" package is also needed if you +would like color too. These can simply be added to +`org-latex-packages-alist', using customise or something like: (require \\='ox-latex) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"listings\")) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"color\")) -Alternatively, +There are two options for more comprehensive fontification. The +first can be set with, + + (setq org-latex-listings \\='engraved) + +which causes source code to be run through +`engrave-faces-latex-buffer', which generates colorings using +Emacs' font-lock information. This requires the engrave-faces +package (availible from ELPA), and the fvextra LaTeX package be +installed. + +The styling of the engraved result can customised with +`org-latex-engraved-preamble' and `org-latex-engraved-options'. +The default preamble also uses the tcolorbox LaTeX package in +addition to fvextra. + +The second more comprehensive option can be used with, (setq org-latex-listings \\='minted) -causes source code to be exported using the minted package as -opposed to listings. If you want to use minted, you need to add -the minted package to `org-latex-packages-alist', for example +which causes source code to be exported using the minted package +as opposed to listings. If you want to use minted, you need to +add the minted package to `org-latex-packages-alist', for example using customize, or with (require \\='ox-latex) @@ -971,8 +1001,9 @@ (defcustom org-latex-listings nil :type '(choice (const :tag "Use listings" t) (const :tag "Use minted" minted) + (const :tag "Use engrave-faces-latex" engraved) (const :tag "Export verbatim" nil)) - :safe (lambda (s) (memq s '(t nil minted)))) + :safe (lambda (s) (memq s '(t nil minted engraved)))) (defcustom org-latex-listings-langs '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp") @@ -1142,6 +1173,124 @@ (defcustom org-latex-custom-lang-environments nil :version "26.1" :package-version '(Org . "9.0")) +(defcustom org-latex-engraved-preamble + "\\usepackage{fvextra} + +[FVEXTRA-SETUP] + +\\renewcommand\\theFancyVerbLine{\\footnotesize\\color{black!40!white}\\arabic{FancyVerbLine}} + +\\usepackage{xcolor} + +\\providecolor{codebackground}{HTML}{f7f7f7} +\\providecolor{codeborder}{HTML}{f0f0f0} +\\providecolor{EFD}{HTML}{28292e} + +% TODO have code boxes keep line vertical alignment +\\usepackage[breakable,xparse]{tcolorbox} +\\DeclareTColorBox[]{Code}{o}% +{colback=codebackground, colframe=codeborder, + fontupper=\\footnotesize\\setlength{\\fboxsep}{0pt}, + colupper=EFD, + IfNoValueTF={#1}% + {boxsep=2pt, arc=2.5pt, outer arc=2.5pt, + boxrule=0.5pt, left=2pt}% + {boxsep=2.5pt, arc=0pt, outer arc=0pt, + boxrule=0pt, leftrule=1.5pt, left=0.5pt}, + right=2pt, top=1pt, bottom=0.5pt, + breakable}" + "Preamble content injected when using engrave-faces-latex for source blocks. +This is relevant when `org-latex-listings' is set to `engraved'. + +There is quite a lot of flexibility in what this preamble can be, as long as it: +- Loads the fvextra package. +- Loads the package xcolor (if it is not already loader elsewhere). +- Defines a \"Code\" environment (note the capital C), which can be + later used to wrap \"Verbatim\" environments (provided by fvextra). + +A macro-like placeholder is used to set fvextra's defaults according to +`org-latex-engraved-options': + + [FVEXTRA-SETUP] + +In the default value the color \"EFD\" is provided as this is the +foreground colour provided by engrave-faces-latex. When there +are example/fixed-width blocks only, the engraved generated +preamble is not included, and so it is provided so we may use it +anyway." + :group 'org-export-latex + :type 'string + :package-version '(Org . "9.6")) + +(defcustom org-latex-engraved-options + '(("commandchars" . "\\\\\\{\\}") + ("highlightcolor" . "white!95!black!80!blue") + ("breaklines" . "true") + ("breaksymbol" . "\\color{white!60!black}\\tiny\\ensuremath{\\hookrightarrow}")) + "Association list of options for the latex fvextra package when engraving code. + +These options are set using \\fvset{...} in the preamble of the +LaTeX export. Each element of the alist should be a list or cons +cell containing two strings: the name of the option, and the +value. For example, + + (setq org-latex-engraved-options + \\='((\"highlightcolor\" \"green\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-engraved-options + \\='((\"highlightcolor\" . \"green\") (\"frame\" . \"lines\"))) + +will result in the following LaTeX in the preamble + +\\fvset{% + bgcolor=bg, + frame=lines} + +This will affect all fvextra environments. Note that the same +options will be applied to all blocks. If you need +block-specific options, you may use the following syntax: + + #+ATTR_LATEX: :options key1=value1,key2=value2 + #+BEGIN_SRC <LANG> + ... + #+END_SRC" + :group 'org-export-latex + :type '(alist :key-type (string :tag "option") + :value-type (string :tag "value"))) + +(defun org-latex-generate-engraved-preamble (info syntax-colours-p) + "Generate the preamble to setup engraved code. +The result is constructed from `org-latex-engraved-preamble' and +`org-latex-engraved-options'." + (let* ((engraved-options + (plist-get info :latex-engraved-options)) + (engraved-preamble-template + (plist-get info :latex-engraved-preamble)) + (engraved-preamble + (if (string-match "^[ \t]*\\[FVEXTRA-SETUP\\][ \t]*\n?" + engraved-preamble) + (replace-match + (concat + "\\fvset{%\n " + (org-latex--make-option-string engraved-options ",\n ") + "}\n") + t t + engraved-preamble-template) + engraved-preamble-template))) + (if syntax-colours-p + (concat + "\n% Setup for code blocks [1/2]\n\n" + engraved-preamble + "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n" + (if (require 'engrave-faces-latex nil t) + (engrave-faces-latex-gen-preamble) + (message "Cannot engrave source blocks. Consider installing `engrave-faces'.") + "% WARNING syntax highlighting unavailible as engrave-faces-latex was missing.\n") + "\n") + (concat + "\n% Setup for code blocks\n\n" + engraved-preamble + "\n")))) ;;;; Compilation @@ -1756,6 +1905,15 @@ (defun org-latex-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template spec))) + ;; engrave-faces-latex preamble + (when (eq org-latex-listings 'engraved) + (let ((src-p (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity)) + (fixedw-p + (org-element-map (plist-get info :parse-tree) + '(example-block fixed-width) #'identity))) + (when (or src-p fixedw-p) + (org-latex-generate-engraved-preamble info src-p)))) ;; Document start. "\\begin{document}\n\n" ;; Title command. @@ -2142,6 +2300,7 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) (pcase (plist-get info :latex-listings) ('nil (org-latex--text-markup code 'code info)) ('minted (org-latex-inline-src-block--minted info code lang)) + ('engraved (org-latex-inline-src-block--engraved info code lang)) (_ (org-latex-inline-src-block--listings info code lang))))) (defun org-latex-inline-src-block--minted (info code lang) @@ -2149,7 +2308,7 @@ (defun org-latex-inline-src-block--minted (info code lang) INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." (let ((mint-lang (or (cadr (assq (intern lang) (plist-get info :latex-minted-langs))) - (downcase org-lang))) + (downcase lang))) (options (org-latex--make-option-string (plist-get info :latex-minted-options)))) (format "\\mintinline%s{%s}{%s}" @@ -2157,6 +2316,24 @@ (defun org-latex-inline-src-block--minted (info code lang) mint-lang code))) +(defun org-latex-inline-src-block--engraved (info code lang) + "Transcode an inline src block's content from Org to LaTeX, using engrave-faces. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (if (require 'engrave-faces-latex nil t) + (let (engraved-buffer engraved-code) + (setq engraved-buffer + (with-temp-buffer + (insert code) + (funcall (org-src-get-lang-mode lang)) + (engrave-faces-latex-buffer))) + (setq engraved-code + (with-current-buffer engraved-buffer + (buffer-string))) + (kill-buffer engraved-buffer) + (format "\\Verb{%s}" + engraved-code)) + (user-error "Cannot engrave inline src block, `engrave-faces-latex' is unavailible."))) + (defun org-latex-inline-src-block--listings (info code lang) "Transcode an inline src block's content from Org to LaTeX, using lstlistings. INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." @@ -3017,6 +3194,9 @@ (defun org-latex-src-block (src-block _contents info) num-start retain-labels attributes float custom-env)) ((eq listings 'minted) (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) + ((eq listings 'engraved) + (org-latex-src-block--engraved src-block info lang caption caption-above-p label num-start retain-labels attributes float)) (t (org-latex-src-block--listings src-block info lang caption caption-above-p label @@ -3133,6 +3313,79 @@ (defun org-latex-src-block--minted ;; Return value. (format float-env body))) +(defun org-latex-src-block--engraved + (src-block info lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using engrave-faces-latex. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (if (require 'engrave-faces-latex nil t) + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-engraved-options)) + (content-buffer + (with-temp-buffer + (insert + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))) + (funcall (org-src-get-lang-mode lang)) + (engrave-faces-latex-buffer))) + (content + (with-current-buffer content-buffer + (buffer-string))) + (body + (format + "\\begin{Code}\n\\begin{Verbatim}[%s]\n%s\\end{Verbatim}\n\\end{Code}" + ;; Options. + (concat + (org-latex--make-option-string + (append + (when (and num-start (not (assoc "linenos" options))) + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (list local-options)))))) + content))) + (kill-buffer content-buffer) + ;; Return value. + (format float-env body)) + (user-error "Cannot engrave src block, `engrave-faces-latex' is unavailible."))) + (defun org-latex-src-block--listings (src-block info lang caption caption-above-p label num-start retain-labels attributes float) -- 2.35.3 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-05 15:17 ` Timothy @ 2022-05-05 16:13 ` Timothy 2022-05-07 5:16 ` Ihor Radchenko 2022-05-05 16:48 ` [PATCH] " Max Nikulin 1 sibling, 1 reply; 27+ messages in thread From: Timothy @ 2022-05-05 16:13 UTC (permalink / raw) To: Ihor Radchenko; +Cc: emacs-orgmode, Daniel Fleischer, Nicolas Goaziou [-- Attachment #1: Type: text/plain, Size: 166 bytes --] > [5. text/x-patch; 0004-ox-latex-Introduce-engraved-code-highlighting.patch]… Ooops, I had some ucommited changes. The correct version is attached. Timothy [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-ox-latex-Introduce-engraved-code-highlighting.patch --] [-- Type: text/x-patch, Size: 17470 bytes --] From b66c291b1f0d1419742449bcde42bf0c4d620c23 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 20:04:12 +0800 Subject: [PATCH] ox-latex: Introduce "engraved" code highlighting * lisp/ox-latex.el (org-latex-src-block, org-latex-src-block--engraved, org-latex-inline-src-block, org-latex-inline-src-block--engraved, org-latex-template, org-latex-listings): Make use of the engraved-faces package (available on ELPA) to provide an alternative LaTeX code highlighting backend which functions similarly to htmlize.el for HTML exports. (org-latex-engraved-preamble, org-latex-engraved-options): Introduce variables to construct the preamble for engraved code blocks. * lisp/ox-beamer.el (org-beamer-template): Modify to add engrave-faces preamble when applicable. --- lisp/ox-beamer.el | 9 ++ lisp/ox-latex.el | 273 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 272 insertions(+), 10 deletions(-) diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 6be73c91e..73bd95539 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -857,6 +857,15 @@ (defun org-beamer-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template (org-latex--format-spec info)))) + ;; engrave-faces-latex preamble + (when (eq org-latex-listings 'engraved) + (let ((src-p (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity)) + (fixedw-p + (org-element-map (plist-get info :parse-tree) + '(example-block fixed-width) #'identity))) + (when (or src-p fixedw-p) + (org-latex-generate-engraved-preamble info src-p)))) ;; Document start. "\\begin{document}\n\n" ;; Title command. diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 4181db175..83bb6f078 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -37,6 +37,8 @@ (defvar org-latex-default-packages-alist) (defvar org-latex-packages-alist) (defvar orgtbl-exp-regexp) +(declare-function engrave-faces-latex-gen-preamble "ext:engrave-faces-latex") +(declare-function engrave-faces-latex-buffer "ext:engrave-faces-latex") \f ;;; Define Back-End @@ -125,6 +127,8 @@ (org-export-define-backend 'latex (:latex-default-quote-environment nil nil org-latex-default-quote-environment) (:latex-default-table-mode nil nil org-latex-default-table-mode) (:latex-diary-timestamp-format nil nil org-latex-diary-timestamp-format) + (:latex-engraved-options nil nil org-latex-engraved-options) + (:latex-engraved-preamble nil nil org-latex-engraved-preamble) (:latex-footnote-defined-format nil nil org-latex-footnote-defined-format) (:latex-footnote-separator nil nil org-latex-footnote-separator) (:latex-format-drawer-function nil nil org-latex-format-drawer-function) @@ -937,22 +941,48 @@ (defcustom org-latex-listings nil "Non-nil means export source code using the listings package. This package will fontify source code, possibly even with color. -If you want to use this, you also need to make LaTeX use the -listings package, and if you want to have color, the color -package. Just add these to `org-latex-packages-alist', for -example using customize, or with something like: +There are four implementations of this functionality you may +choose from (ordered from least to most capable): +1. Verbatim (nil) +2. Listings (t) +3. Minted (minted) +4. Engraved (engraved) + +The first two options provide basic syntax +highlighting (listings), or none at all (verbatim). + +When using listings, you also need to make use of the LaTeX +\"listings\" package. The \"color\" package is also needed if you +would like color too. These can simply be added to +`org-latex-packages-alist', using customise or something like: (require \\='ox-latex) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"listings\")) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"color\")) -Alternatively, +There are two options for more comprehensive fontification. The +first can be set with, + + (setq org-latex-listings \\='engraved) + +which causes source code to be run through +`engrave-faces-latex-buffer', which generates colorings using +Emacs' font-lock information. This requires the engrave-faces +package (availible from ELPA), and the fvextra LaTeX package be +installed. + +The styling of the engraved result can customised with +`org-latex-engraved-preamble' and `org-latex-engraved-options'. +The default preamble also uses the tcolorbox LaTeX package in +addition to fvextra. + +The second more comprehensive option can be used with, (setq org-latex-listings \\='minted) -causes source code to be exported using the minted package as -opposed to listings. If you want to use minted, you need to add -the minted package to `org-latex-packages-alist', for example +which causes source code to be exported using the minted package +as opposed to listings. If you want to use minted, you need to +add the minted package to `org-latex-packages-alist', for example using customize, or with (require \\='ox-latex) @@ -971,8 +1001,9 @@ (defcustom org-latex-listings nil :type '(choice (const :tag "Use listings" t) (const :tag "Use minted" minted) + (const :tag "Use engrave-faces-latex" engraved) (const :tag "Export verbatim" nil)) - :safe (lambda (s) (memq s '(t nil minted)))) + :safe (lambda (s) (memq s '(t nil minted engraved)))) (defcustom org-latex-listings-langs '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp") @@ -1142,6 +1173,124 @@ (defcustom org-latex-custom-lang-environments nil :version "26.1" :package-version '(Org . "9.0")) +(defcustom org-latex-engraved-preamble + "\\usepackage{fvextra} + +[FVEXTRA-SETUP] + +\\renewcommand\\theFancyVerbLine{\\footnotesize\\color{black!40!white}\\arabic{FancyVerbLine}} + +\\usepackage{xcolor} + +\\providecolor{codebackground}{HTML}{f7f7f7} +\\providecolor{codeborder}{HTML}{f0f0f0} +\\providecolor{EFD}{HTML}{28292e} + +% TODO have code boxes keep line vertical alignment +\\usepackage[breakable,xparse]{tcolorbox} +\\DeclareTColorBox[]{Code}{o}% +{colback=codebackground, colframe=codeborder, + fontupper=\\footnotesize\\setlength{\\fboxsep}{0pt}, + colupper=EFD, + IfNoValueTF={#1}% + {boxsep=2pt, arc=2.5pt, outer arc=2.5pt, + boxrule=0.5pt, left=2pt}% + {boxsep=2.5pt, arc=0pt, outer arc=0pt, + boxrule=0pt, leftrule=1.5pt, left=0.5pt}, + right=2pt, top=1pt, bottom=0.5pt, + breakable}" + "Preamble content injected when using engrave-faces-latex for source blocks. +This is relevant when `org-latex-listings' is set to `engraved'. + +There is quite a lot of flexibility in what this preamble can be, as long as it: +- Loads the fvextra package. +- Loads the package xcolor (if it is not already loader elsewhere). +- Defines a \"Code\" environment (note the capital C), which can be + later used to wrap \"Verbatim\" environments (provided by fvextra). + +A macro-like placeholder is used to set fvextra's defaults according to +`org-latex-engraved-options': + + [FVEXTRA-SETUP] + +In the default value the color \"EFD\" is provided as this is the +foreground colour provided by engrave-faces-latex. When there +are example/fixed-width blocks only, the engraved generated +preamble is not included, and so it is provided so we may use it +anyway." + :group 'org-export-latex + :type 'string + :package-version '(Org . "9.6")) + +(defcustom org-latex-engraved-options + '(("commandchars" . "\\\\\\{\\}") + ("highlightcolor" . "white!95!black!80!blue") + ("breaklines" . "true") + ("breaksymbol" . "\\color{white!60!black}\\tiny\\ensuremath{\\hookrightarrow}")) + "Association list of options for the latex fvextra package when engraving code. + +These options are set using \\fvset{...} in the preamble of the +LaTeX export. Each element of the alist should be a list or cons +cell containing two strings: the name of the option, and the +value. For example, + + (setq org-latex-engraved-options + \\='((\"highlightcolor\" \"green\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-engraved-options + \\='((\"highlightcolor\" . \"green\") (\"frame\" . \"lines\"))) + +will result in the following LaTeX in the preamble + +\\fvset{% + bgcolor=bg, + frame=lines} + +This will affect all fvextra environments. Note that the same +options will be applied to all blocks. If you need +block-specific options, you may use the following syntax: + + #+ATTR_LATEX: :options key1=value1,key2=value2 + #+BEGIN_SRC <LANG> + ... + #+END_SRC" + :group 'org-export-latex + :type '(alist :key-type (string :tag "option") + :value-type (string :tag "value"))) + +(defun org-latex-generate-engraved-preamble (info syntax-colours-p) + "Generate the preamble to setup engraved code. +The result is constructed from `org-latex-engraved-preamble' and +`org-latex-engraved-options'." + (let* ((engraved-options + (plist-get info :latex-engraved-options)) + (engraved-preamble-template + (plist-get info :latex-engraved-preamble)) + (engraved-preamble + (if (string-match "^[ \t]*\\[FVEXTRA-SETUP\\][ \t]*\n?" + engraved-preamble-template) + (replace-match + (concat + "\\fvset{%\n " + (org-latex--make-option-string engraved-options ",\n ") + "}\n") + t t + engraved-preamble-template) + engraved-preamble-template))) + (if syntax-colours-p + (concat + "\n% Setup for code blocks [1/2]\n\n" + engraved-preamble + "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n" + (if (require 'engrave-faces-latex nil t) + (engrave-faces-latex-gen-preamble) + (message "Cannot engrave source blocks. Consider installing `engrave-faces'.") + "% WARNING syntax highlighting unavailible as engrave-faces-latex was missing.\n") + "\n") + (concat + "\n% Setup for code blocks\n\n" + engraved-preamble + "\n")))) ;;;; Compilation @@ -1756,6 +1905,15 @@ (defun org-latex-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template spec))) + ;; engrave-faces-latex preamble + (when (eq org-latex-listings 'engraved) + (let ((src-p (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity)) + (fixedw-p + (org-element-map (plist-get info :parse-tree) + '(example-block fixed-width) #'identity))) + (when (or src-p fixedw-p) + (org-latex-generate-engraved-preamble info src-p)))) ;; Document start. "\\begin{document}\n\n" ;; Title command. @@ -2142,6 +2300,7 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) (pcase (plist-get info :latex-listings) ('nil (org-latex--text-markup code 'code info)) ('minted (org-latex-inline-src-block--minted info code lang)) + ('engraved (org-latex-inline-src-block--engraved info code lang)) (_ (org-latex-inline-src-block--listings info code lang))))) (defun org-latex-inline-src-block--minted (info code lang) @@ -2149,7 +2308,7 @@ (defun org-latex-inline-src-block--minted (info code lang) INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." (let ((mint-lang (or (cadr (assq (intern lang) (plist-get info :latex-minted-langs))) - (downcase org-lang))) + (downcase lang))) (options (org-latex--make-option-string (plist-get info :latex-minted-options)))) (format "\\mintinline%s{%s}{%s}" @@ -2157,6 +2316,24 @@ (defun org-latex-inline-src-block--minted (info code lang) mint-lang code))) +(defun org-latex-inline-src-block--engraved (_info code lang) + "Transcode an inline src block's content from Org to LaTeX, using engrave-faces. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (if (require 'engrave-faces-latex nil t) + (let (engraved-buffer engraved-code) + (setq engraved-buffer + (with-temp-buffer + (insert code) + (funcall (org-src-get-lang-mode lang)) + (engrave-faces-latex-buffer))) + (setq engraved-code + (with-current-buffer engraved-buffer + (buffer-string))) + (kill-buffer engraved-buffer) + (format "\\Verb{%s}" + engraved-code)) + (user-error "Cannot engrave inline src block, `engrave-faces-latex' is unavailible."))) + (defun org-latex-inline-src-block--listings (info code lang) "Transcode an inline src block's content from Org to LaTeX, using lstlistings. INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." @@ -3017,6 +3194,9 @@ (defun org-latex-src-block (src-block _contents info) num-start retain-labels attributes float custom-env)) ((eq listings 'minted) (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) + ((eq listings 'engraved) + (org-latex-src-block--engraved src-block info lang caption caption-above-p label num-start retain-labels attributes float)) (t (org-latex-src-block--listings src-block info lang caption caption-above-p label @@ -3133,6 +3313,79 @@ (defun org-latex-src-block--minted ;; Return value. (format float-env body))) +(defun org-latex-src-block--engraved + (src-block info lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using engrave-faces-latex. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (if (require 'engrave-faces-latex nil t) + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-engraved-options)) + (content-buffer + (with-temp-buffer + (insert + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))) + (funcall (org-src-get-lang-mode lang)) + (engrave-faces-latex-buffer))) + (content + (with-current-buffer content-buffer + (buffer-string))) + (body + (format + "\\begin{Code}\n\\begin{Verbatim}[%s]\n%s\\end{Verbatim}\n\\end{Code}" + ;; Options. + (concat + (org-latex--make-option-string + (append + (when (and num-start (not (assoc "linenos" options))) + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (list local-options)))))) + content))) + (kill-buffer content-buffer) + ;; Return value. + (format float-env body)) + (user-error "Cannot engrave src block, `engrave-faces-latex' is unavailible."))) + (defun org-latex-src-block--listings (src-block info lang caption caption-above-p label num-start retain-labels attributes float) -- 2.35.3 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-05 16:13 ` Timothy @ 2022-05-07 5:16 ` Ihor Radchenko 2022-05-07 6:57 ` Timothy 0 siblings, 1 reply; 27+ messages in thread From: Ihor Radchenko @ 2022-05-07 5:16 UTC (permalink / raw) To: Timothy; +Cc: emacs-orgmode, Daniel Fleischer, Nicolas Goaziou Timothy <tecosaur@gmail.com> writes: Thanks for the updated patch! See some more comments below. > +The first two options provide basic syntax > +highlighting (listings), or none at all (verbatim). > ... > -Alternatively, > +There are two options for more comprehensive fontification. The > +first can be set with, Maybe "The other two options"? Also, using first/second here is a bit confusing because: (1) they are actually 3/4 in the above list; (2) engraved is listed last. > +The second more comprehensive option can be used with, *can be set with > -causes source code to be exported using the minted package as > -opposed to listings. If you want to use minted, you need to add > -the minted package to `org-latex-packages-alist', for example > +which causes source code to be exported using the minted package > +as opposed to listings. If you want to use minted, you need to > +add the minted package to `org-latex-packages-alist', for example > using customize, or with I feel slightly confused about using the word "package" here. Which one refers to LaTeX package and which one to Emacs? I would state "Emacs package" explicitly to highlight contrast with "LaTeX package". > +(defcustom org-latex-engraved-preamble > + "\\usepackage{fvextra} > + > +[FVEXTRA-SETUP] > + > +\\renewcommand\\theFancyVerbLine{\\footnotesize\\color{black!40!white}\\arabic{FancyVerbLine}} I'd like to see a comment on what it does. > +\\usepackage{xcolor} > + > +\\providecolor{codebackground}{HTML}{f7f7f7} > +\\providecolor{codeborder}{HTML}{f0f0f0} > +\\providecolor{EFD}{HTML}{28292e} > + > +% TODO have code boxes keep line vertical alignment > +\\usepackage[breakable,xparse]{tcolorbox} > +\\DeclareTColorBox[]{Code}{o}% Same request to provide a comment. Also, what it that % TODO doing there? It is confusing. Also, it is unclear what the [breakable,xparse] options to tcolorbox are doing there and what will happen if the user removes them. Further, I am wondering what is going to happen if the user happens to have tcolorbox without options loaded via org-latex-packages-alist. > +There is quite a lot of flexibility in what this preamble can be, as long as it: > +- Loads the fvextra package. > +- Loads the package xcolor (if it is not already loader elsewhere). > +- Defines a \"Code\" environment (note the capital C), which can be > + later used to wrap \"Verbatim\" environments (provided by fvextra). The last point is not very clear. What kind of environment? > +(defun org-latex-generate-engraved-preamble (info syntax-colours-p) > + "Generate the preamble to setup engraved code. > +The result is constructed from `org-latex-engraved-preamble' and > +`org-latex-engraved-options'." This is relying on (:latex-engraved-options nil nil org-latex-engraved-options) (:latex-engraved-preamble nil nil org-latex-engraved-preamble) If it changes any time in future (e.g. to allow per-file settings), the docstring may be overlooked. > + (let ((src-p (org-element-map (plist-get info :parse-tree) > + '(src-block inline-src-block) #'identity)) > + (fixedw-p > + (org-element-map (plist-get info :parse-tree) > + '(example-block fixed-width) #'identity))) I'd use FIRST-MATCH argument for org-element-map. It will be slightly faster on large buffers. > - (downcase org-lang))) > + (downcase lang))) I am not sure if this belongs to this patch. Please double check. > + (mapcar 'length > + (org-split-string (car code-info) > + "\n"))))) I am not sure how well it will work with e.g. Chinese characters in comments. Best, Ihor ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-07 5:16 ` Ihor Radchenko @ 2022-05-07 6:57 ` Timothy 2022-05-07 10:40 ` Timothy 0 siblings, 1 reply; 27+ messages in thread From: Timothy @ 2022-05-07 6:57 UTC (permalink / raw) To: Ihor Radchenko; +Cc: emacs-orgmode, Daniel Fleischer, Nicolas Goaziou [-- Attachment #1: Type: text/plain, Size: 3409 bytes --] Hi Ihor, Find attached an updated patchset, and comments below :) Ihor Radchenko <yantar92@gmail.com> writes: > Maybe “The other two options”? Also, using first/second here is a bit > confusing because: (1) they are actually 3/4 in the above list; (2) > engraved is listed last. Docstring changed. >> +The second more comprehensive option can be used with, > > *can be set with Changed. > I feel slightly confused about using the word “package” here. Which one > refers to LaTeX package and which one to Emacs? I would state “Emacs > package” explicitly to highlight contrast with “LaTeX package”. Clarifications added to the docstring. >> +\\{\\\FancyVerbLine} > > I’d like to see a comment on what it does. Added. > Same request to provide a comment. Also, what it that % TODO doing > there? It is confusing. A comment has been added, and the TODO removed. > Also, it is unclear what the [breakable,xparse] options to tcolorbox are > doing there and what will happen if the user removes them. “breakable” allows the box to be broken across pages, and “xparse” provides `\DeclareTColorBox'. > Further, I am wondering what is going to happen if the user happens to > have tcolorbox without options loaded via org-latex-packages-alist. They could see: ERROR: LaTeX Error: Option clash for package tcolorbox. They would need to tweak such a tcolorbox entry to include the options used here. >> +There is quite a lot of flexibility in what this preamble can be, as long as it: >> +- Loads the fvextra package. >> +- Loads the package xcolor (if it is not already loader elsewhere). >> +- Defines a \“Code\” environment (note the capital C), which can be >> + later used to wrap \“Verbatim\” environments (provided by fvextra). > > The last point is not very clear. What kind of environment? Anything that the user wants to do to modify the display of the generated `Verbatim' environment. >> +(defun org-latex-generate-engraved-preamble (info syntax-colours-p) >> + “Generate the preamble to setup engraved code. >> +The result is constructed from `org-latex-engraved-preamble’ and >> +`org-latex-engraved-options’.” > > This is relying on > > (:latex-engraved-options nil nil org-latex-engraved-options) > (:latex-engraved-preamble nil nil org-latex-engraved-preamble) > > If it changes any time in future (e.g. to allow per-file settings), the > docstring may be overlooked. Docstring tweaked. > I’d use FIRST-MATCH argument for org-element-map. It will be slightly > faster on large buffers. Ah nice, I’ll make use of that. >> - (downcase org-lang))) >> + (downcase lang))) > > I am not sure if this belongs to this patch. Please double check. Ooops, moved to the correct patch. >> + (mapcar ’length >> + (org-split-string (car code-info) >> + “”))))) > > I am not sure how well it will work with e.g. Chinese characters in comments. I’ve added a patch replacing `length' with `string-width' > Maybe the functions could be rewritten using cl-defun with keys and > &allow-other-keys and then called via apply on a let-bound arg plist? Done. All the best, Timothy [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-ox-latex-Refactor-org-latex-src-block.patch --] [-- Type: text/x-patch, Size: 15942 bytes --] From d231437e2c9f96bf70520d9ddda810a95667fcdd Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 14:35:34 +0800 Subject: [PATCH 1/7] ox-latex: Refactor `org-latex-src-block' * lisp/ox-latex.el (org-latex-src-block): Extract the per-format logic from `org-latex-src-block' into new dedicated functions: + `org-latex-src-block--verbatim' + `org-latex-src-block--custom' + `org-latex-src-block--minted' + `org-latex-src-block--listings' This makes `org-latex-src-block' much less monolithic, taking it from 175 lines to 30, and I find also makes it easier to understand. --- lisp/ox-latex.el | 339 ++++++++++++++++++++++++++--------------------- 1 file changed, 185 insertions(+), 154 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 841ad48bc..c2f728a1c 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2997,164 +2997,195 @@ (defun org-latex-src-block (src-block _contents info) (float (plist-get attributes :float)) (listings (plist-get info :latex-listings))) (cond - ;; Case 1. No source fontification. ((or (not lang) (not listings)) - (let ((caption-str (org-latex--caption/label-string src-block info)) - (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" - (org-export-format-code-default src-block info)))) - (cond ((string= "multicolumn" float) - (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" - (plist-get info :latex-default-figure-position) - (if caption-above-p caption-str "") - verbatim - (if caption-above-p "" caption-str))) - (caption (concat - (if caption-above-p caption-str "") - verbatim - (if caption-above-p "" (concat "\n" caption-str)))) - (t verbatim)))) - ;; Case 2. Custom environment. + (org-latex-src-block--verbatim src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) (custom-env - (let ((caption-str (org-latex--caption/label-string src-block info)) - (formatted-src (org-export-format-code-default src-block info))) - (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) - (format "\\begin{%s}\n%s\\end{%s}\n" - custom-env - (concat (and caption-above-p caption-str) - formatted-src - (and (not caption-above-p) caption-str)) - custom-env) - (format-spec custom-env - `((?s . ,formatted-src) - (?c . ,caption) - (?f . ,float) - (?l . ,(org-latex--label src-block info)) - (?o . ,(or (plist-get attributes :options) ""))))))) - ;; Case 3. Use minted package. + (org-latex-src-block--custom src-block info lang caption caption-above-p label + num-start retain-labels attributes float custom-env)) ((eq listings 'minted) - (let* ((caption-str (org-latex--caption/label-string src-block info)) - (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) - (plist-get info :latex-default-figure-position))) - (float-env - (cond - ((string= "multicolumn" float) - (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - (caption - (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - ((string= "t" float) - (concat (format "\\begin{listing}[%s]\n" - placement) - "%s\n\\end{listing}")) - (t "%s"))) - (options (plist-get info :latex-minted-options)) - (body - (format - "\\begin{minted}[%s]{%s}\n%s\\end{minted}" - ;; Options. - (concat - (org-latex--make-option-string - (if (or (not num-start) (assoc "linenos" options)) - options - (append - `(("linenos") - ("firstnumber" ,(number-to-string (1+ num-start)))) - options))) - (let ((local-options (plist-get attributes :options))) - (and local-options (concat "," local-options)))) - ;; Language. - (or (cadr (assq (intern lang) - (plist-get info :latex-minted-langs))) - (downcase lang)) - ;; Source code. - (let* ((code-info (org-export-unravel-code src-block)) - (max-width - (apply 'max - (mapcar 'length - (org-split-string (car code-info) - "\n"))))) - (org-export-format-code - (car code-info) - (lambda (loc _num ref) - (concat - loc - (when ref - ;; Ensure references are flushed to the right, - ;; separated with 6 spaces from the widest line - ;; of code. - (concat (make-string (+ (- max-width (length loc)) 6) - ?\s) - (format "(%s)" ref))))) - nil (and retain-labels (cdr code-info))))))) - ;; Return value. - (format float-env body))) - ;; Case 4. Use listings package. + (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) (t - (let ((lst-lang - (or (cadr (assq (intern lang) - (plist-get info :latex-listings-langs))) - lang)) - (caption-str - (when caption - (let ((main (org-export-get-caption src-block)) - (secondary (org-export-get-caption src-block t))) - (if (not secondary) - (format "{%s}" (org-export-data main info)) - (format "{[%s]%s}" - (org-export-data secondary info) - (org-export-data main info)))))) - (lst-opt (plist-get info :latex-listings-options))) - (concat - ;; Options. - (format - "\\lstset{%s}\n" - (concat - (org-latex--make-option-string - (append - lst-opt - (cond - ((and (not float) (plist-member attributes :float)) nil) - ((string= "multicolumn" float) '(("float" "*"))) - ((and float (not (assoc "float" lst-opt))) - `(("float" ,(plist-get info :latex-default-figure-position))))) - `(("language" ,lst-lang)) - (if label - `(("label" ,(org-latex--label src-block info))) - '(("label" " "))) - (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) - `(("captionpos" ,(if caption-above-p "t" "b"))) - (cond ((assoc "numbers" lst-opt) nil) - ((not num-start) '(("numbers" "none"))) - (t `(("firstnumber" ,(number-to-string (1+ num-start))) - ("numbers" "left")))))) - (let ((local-options (plist-get attributes :options))) - (and local-options (concat "," local-options))))) - ;; Source code. - (format - "\\begin{lstlisting}\n%s\\end{lstlisting}" - (let* ((code-info (org-export-unravel-code src-block)) - (max-width - (apply 'max - (mapcar 'length - (org-split-string (car code-info) "\n"))))) - (org-export-format-code - (car code-info) - (lambda (loc _num ref) - (concat - loc - (when ref - ;; Ensure references are flushed to the right, - ;; separated with 6 spaces from the widest line of - ;; code - (concat (make-string (+ (- max-width (length loc)) 6) ?\s) - (format "(%s)" ref))))) - nil (and retain-labels (cdr code-info)))))))))))) - + (org-latex-src-block--listings src-block info lang caption caption-above-p label + num-start retain-labels attributes float)))))) + +(defun org-latex-src-block--verbatim + (src-block info _lang caption caption-above-p _label + _num-start _retain-labels _attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using verbatim. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((caption-str (org-latex--caption/label-string src-block info)) + (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" + (org-export-format-code-default src-block info)))) + (cond ((string= "multicolumn" float) + (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" + (plist-get info :latex-default-figure-position) + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" caption-str))) + (caption (concat + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" (concat "\n" caption-str)))) + (t verbatim)))) + +(defun org-latex-src-block--custom + (src-block info _lang caption caption-above-p _label + _num-start _retain-labels attributes float custom-env) + "Transcode a SRC-BLOCK element from Org to LaTeX, using a custom environment. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((caption-str (org-latex--caption/label-string src-block info)) + (formatted-src (org-export-format-code-default src-block info))) + (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) + (format "\\begin{%s}\n%s\\end{%s}\n" + custom-env + (concat (and caption-above-p caption-str) + formatted-src + (and (not caption-above-p) caption-str)) + custom-env) + (format-spec custom-env + `((?s . ,formatted-src) + (?c . ,caption) + (?f . ,float) + (?l . ,(org-latex--label src-block info)) + (?o . ,(or (plist-get attributes :options) ""))))))) + +(defun org-latex-src-block--minted + (src-block info lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using minted. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-minted-options)) + (body + (format + "\\begin{minted}[%s]{%s}\n%s\\end{minted}" + ;; Options. + (concat + (org-latex--make-option-string + (if (or (not num-start) (assoc "linenos" options)) + options + (append + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start)))) + options))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options)))) + ;; Language. + (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase lang)) + ;; Source code. + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))))) + ;; Return value. + (format float-env body))) + +(defun org-latex-src-block--listings + (src-block info lang caption caption-above-p label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using listings. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((lst-lang + (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + lang)) + (caption-str + (when caption + (let ((main (org-export-get-caption src-block)) + (secondary (org-export-get-caption src-block t))) + (if (not secondary) + (format "{%s}" (org-export-data main info)) + (format "{[%s]%s}" + (org-export-data secondary info) + (org-export-data main info)))))) + (lst-opt (plist-get info :latex-listings-options))) + (concat + ;; Options. + (format + "\\lstset{%s}\n" + (concat + (org-latex--make-option-string + (append + lst-opt + (cond + ((and (not float) (plist-member attributes :float)) nil) + ((string= "multicolumn" float) '(("float" "*"))) + ((and float (not (assoc "float" lst-opt))) + `(("float" ,(plist-get info :latex-default-figure-position))))) + `(("language" ,lst-lang)) + (if label + `(("label" ,(org-latex--label src-block info))) + '(("label" " "))) + (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) + `(("captionpos" ,(if caption-above-p "t" "b"))) + (cond ((assoc "numbers" lst-opt) nil) + ((not num-start) '(("numbers" "none"))) + (t `(("firstnumber" ,(number-to-string (1+ num-start))) + ("numbers" "left")))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options))))) + ;; Source code. + (format + "\\begin{lstlisting}\n%s\\end{lstlisting}" + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line of + ;; code + (concat (make-string (+ (- max-width (length loc)) 6) ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info)))))))) ;;;; Statistics Cookie -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-ox-latex-Refactor-org-latex-inline-src-block.patch --] [-- Type: text/x-patch, Size: 4016 bytes --] From aa8406ce64507b870322495e8f9b54317930ed24 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 4 May 2022 18:53:10 +0800 Subject: [PATCH 2/7] ox-latex: Refactor `org-latex-inline-src-block' * lisp/ox-latex.el (org-latex-inline-src-block, org-latex-inline-src-block--minted, org-latex-inline-src-block--listings): Extract the minted and listings specific logic out of `org-latex-inline-src-block` into the new functions `org-latex-inline-src-block--minted` and `org-latex-inline-src-block--listings`. --- lisp/ox-latex.el | 62 +++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index c2f728a1c..38f36a1f3 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2127,36 +2127,38 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) "Transcode an INLINE-SRC-BLOCK element from Org to LaTeX. CONTENTS holds the contents of the item. INFO is a plist holding contextual information." - (let* ((code (org-element-property :value inline-src-block)) - (separator (org-latex--find-verb-separator code))) - (cl-case (plist-get info :latex-listings) - ;; Do not use a special package: transcode it verbatim, as code. - ((nil) (org-latex--text-markup code 'code info)) - ;; Use minted package. - (minted - (let* ((org-lang (org-element-property :language inline-src-block)) - (mint-lang (or (cadr (assq (intern org-lang) - (plist-get info :latex-minted-langs))) - (downcase org-lang))) - (options (org-latex--make-option-string - (plist-get info :latex-minted-options)))) - (format "\\mintinline%s{%s}{%s}" - (if (string= options "") "" (format "[%s]" options)) - mint-lang - code))) - ;; Use listings package. - (otherwise - ;; Maybe translate language's name. - (let* ((org-lang (org-element-property :language inline-src-block)) - (lst-lang (or (cadr (assq (intern org-lang) - (plist-get info :latex-listings-langs))) - org-lang)) - (options (org-latex--make-option-string - (append (plist-get info :latex-listings-options) - `(("language" ,lst-lang)))))) - (concat (format "\\lstinline[%s]" options) - separator code separator)))))) - + (let ((code (org-element-property :value inline-src-block)) + (lang (org-element-property :language inline-src-block))) + (pcase (plist-get info :latex-listings) + ('nil (org-latex--text-markup code 'code info)) + ('minted (org-latex-inline-src-block--minted info code lang)) + (_ (org-latex-inline-src-block--listings info code lang))))) + +(defun org-latex-inline-src-block--minted (info code lang) + "Transcode an inline src block's content from Org to LaTeX, using minted. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (let ((mint-lang (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase lang))) + (options (org-latex--make-option-string + (plist-get info :latex-minted-options)))) + (format "\\mintinline%s{%s}{%s}" + (if (string= options "") "" (format "[%s]" options)) + mint-lang + code))) + +(defun org-latex-inline-src-block--listings (info code lang) + "Transcode an inline src block's content from Org to LaTeX, using lstlistings. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (let* ((lst-lang (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + lang)) + (separator (org-latex--find-verb-separator code)) + (options (org-latex--make-option-string + (append (plist-get info :latex-listings-options) + `(("language" ,lst-lang)))))) + (concat (format "\\lstinline[%s]" options) + separator code separator))) ;;;; Inlinetask -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-ox-latex-More-versitile-option-construction.patch --] [-- Type: text/x-patch, Size: 4116 bytes --] From 62d6703f0dd622916dff8aab960db6df4cb58cf7 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 4 May 2022 23:31:59 +0800 Subject: [PATCH 3/7] ox-latex: More versitile option construction * lisp/ox-latex.el (org-latex--make-option-string): Support a custom option seperator string. (org-latex--make-option-string, org-latex-minted-options, org-latex-listings-options): The first line of the docstrings for `org-latex-minted-options` and `org-latex-listings-options` describe the variables as "association lists", yet `org-latex--make-option-string` does not handle association lists and an example of two-value lists is provided. To make the behaviour match the docstring, `org-latex--make-option-string` is modified to work with either a list two-value lists or an association list, and the examples in `org-latex-minted-options` and `org-latex-listings-options` updated accordingly. --- lisp/ox-latex.el | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 38f36a1f3..2d4b3bace 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -1006,12 +1006,16 @@ (defcustom org-latex-listings-options nil These options are supplied as a comma-separated list to the \\lstset command. Each element of the association list should be -a list containing two strings: the name of the option, and the -value. For example, +a list or cons cell containing two strings: the name of the +option, and the value. For example, (setq org-latex-listings-options \\='((\"basicstyle\" \"\\\\small\") (\"keywordstyle\" \"\\\\color{black}\\\\bfseries\\\\underbar\"))) + ; or + (setq org-latex-listings-options + \\='((\"basicstyle\" . \"\\\\small\") + (\"keywordstyle\" . \"\\\\color{black}\\\\bfseries\\\\underbar\"))) will typeset the code in a small size font with underlined, bold black keywords. @@ -1059,11 +1063,14 @@ (defcustom org-latex-minted-options nil These options are supplied within square brackets in \\begin{minted} environments. Each element of the alist should -be a list containing two strings: the name of the option, and the -value. For example, +be a list or cons cell containing two strings: the name of the +option, and the value. For example, (setq org-latex-minted-options \\='((\"bgcolor\" \"bg\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-minted-options + \\='((\"bgcolor\" . \"bg\") (\"frame\" . \"lines\"))) will result in source blocks being exported with @@ -1506,21 +1513,24 @@ (defun org-latex--find-verb-separator (s) when (not (string-match (regexp-quote (char-to-string c)) s)) return (char-to-string c)))) -(defun org-latex--make-option-string (options) +(defun org-latex--make-option-string (options &optional seperator) "Return a comma separated string of keywords and values. OPTIONS is an alist where the key is the options keyword as a string, and the value a list containing the keyword value, or nil." (mapconcat (lambda (pair) - (pcase-let ((`(,keyword ,value) pair)) - (concat keyword - (and (> (length value) 0) - (concat "=" - (if (string-match-p (rx (any "[]")) value) - (format "{%s}" value) - value)))))) - options - ",")) + (let ((keyword (car pair)) + (value (pcase (cdr pair) + ((pred stringp) (cdr pair)) + ((pred consp) (cadr pair))))) + (concat keyword + (when value + (concat "=" + (if (string-match-p (rx (any "[]")) value) + (format "{%s}" value) + value)))))) + options + (or seperator ","))) (defun org-latex--wrap-label (element output info) "Wrap label associated to ELEMENT around OUTPUT, if appropriate. -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-ox-latex-Introduce-engraved-code-highlighting.patch --] [-- Type: text/x-patch, Size: 17266 bytes --] From 410fda41ae1efa67313ebbe2ada381c5d0f0a092 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 20:04:12 +0800 Subject: [PATCH 4/7] ox-latex: Introduce "engraved" code highlighting * lisp/ox-latex.el (org-latex-src-block, org-latex-src-block--engraved, org-latex-inline-src-block, org-latex-inline-src-block--engraved, org-latex-template, org-latex-listings): Make use of the engraved-faces package (available on ELPA) to provide an alternative LaTeX code highlighting backend which functions similarly to htmlize.el for HTML exports. (org-latex-engraved-preamble, org-latex-engraved-options): Introduce variables to construct the preamble for engraved code blocks. * lisp/ox-beamer.el (org-beamer-template): Modify to add engrave-faces preamble when applicable. --- lisp/ox-beamer.el | 11 ++ lisp/ox-latex.el | 276 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 278 insertions(+), 9 deletions(-) diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 6be73c91e..4d40f6a1d 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -857,6 +857,17 @@ (defun org-beamer-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template (org-latex--format-spec info)))) + ;; engrave-faces-latex preamble + (when (eq org-latex-listings 'engraved) + (let ((src-p (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity + info t)) + (fixedw-p + (org-element-map (plist-get info :parse-tree) + '(example-block fixed-width) #'identity + info t))) + (when (or src-p fixedw-p) + (org-latex-generate-engraved-preamble info src-p)))) ;; Document start. "\\begin{document}\n\n" ;; Title command. diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 2d4b3bace..b9c6d4c3e 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -37,6 +37,8 @@ (defvar org-latex-default-packages-alist) (defvar org-latex-packages-alist) (defvar orgtbl-exp-regexp) +(declare-function engrave-faces-latex-gen-preamble "ext:engrave-faces-latex") +(declare-function engrave-faces-latex-buffer "ext:engrave-faces-latex") \f ;;; Define Back-End @@ -125,6 +127,8 @@ (org-export-define-backend 'latex (:latex-default-quote-environment nil nil org-latex-default-quote-environment) (:latex-default-table-mode nil nil org-latex-default-table-mode) (:latex-diary-timestamp-format nil nil org-latex-diary-timestamp-format) + (:latex-engraved-options nil nil org-latex-engraved-options) + (:latex-engraved-preamble nil nil org-latex-engraved-preamble) (:latex-footnote-defined-format nil nil org-latex-footnote-defined-format) (:latex-footnote-separator nil nil org-latex-footnote-separator) (:latex-format-drawer-function nil nil org-latex-format-drawer-function) @@ -937,22 +941,48 @@ (defcustom org-latex-listings nil "Non-nil means export source code using the listings package. This package will fontify source code, possibly even with color. -If you want to use this, you also need to make LaTeX use the -listings package, and if you want to have color, the color -package. Just add these to `org-latex-packages-alist', for -example using customize, or with something like: +There are four implementations of this functionality you may +choose from (ordered from least to most capable): +1. Verbatim (nil) +2. Listings (t) +3. Minted (minted) +4. Engraved (engraved) + +The first two options provide basic syntax +highlighting (listings), or none at all (verbatim). + +When using listings, you also need to make use of the LaTeX +\"listings\" package. The \"color\" package is also needed if you +would like color too. These can simply be added to +`org-latex-packages-alist', using customise or something like: (require \\='ox-latex) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"listings\")) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"color\")) -Alternatively, +There are two further options for more comprehensive +fontification. The first can be set with, + + (setq org-latex-listings \\='engraved) + +which causes source code to be run through +`engrave-faces-latex-buffer', which generates colorings using +Emacs' font-lock information. This requires the engrave-faces +package (availible from ELPA), and the fvextra LaTeX package be +installed. + +The styling of the engraved result can customised with +`org-latex-engraved-preamble' and `org-latex-engraved-options'. +The default preamble also uses the tcolorbox LaTeX package in +addition to fvextra. + +The second more comprehensive option can be set with, (setq org-latex-listings \\='minted) -causes source code to be exported using the minted package as -opposed to listings. If you want to use minted, you need to add -the minted package to `org-latex-packages-alist', for example +which causes source code to be exported using the minted package +as opposed to listings. If you want to use minted, you need to +add the minted package to `org-latex-packages-alist', for example using customize, or with (require \\='ox-latex) @@ -971,8 +1001,9 @@ (defcustom org-latex-listings nil :type '(choice (const :tag "Use listings" t) (const :tag "Use minted" minted) + (const :tag "Use engrave-faces-latex" engraved) (const :tag "Export verbatim" nil)) - :safe (lambda (s) (memq s '(t nil minted)))) + :safe (lambda (s) (memq s '(t nil minted engraved)))) (defcustom org-latex-listings-langs '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp") @@ -1142,6 +1173,127 @@ (defcustom org-latex-custom-lang-environments nil :version "26.1" :package-version '(Org . "9.0")) +(defcustom org-latex-engraved-preamble + "\\usepackage{fvextra} + +[FVEXTRA-SETUP] + +% Make line numbers smaller and grey. +\\renewcommand\\theFancyVerbLine{\\footnotesize\\color{black!40!white}\\arabic{FancyVerbLine}} + +\\usepackage{xcolor} + +\\providecolor{codebackground}{HTML}{f7f7f7} +\\providecolor{codeborder}{HTML}{f0f0f0} +\\providecolor{EFD}{HTML}{28292e} + +% Define a Code environment to prettily wrap the fontified code. +\\usepackage[breakable,xparse]{tcolorbox} +\\DeclareTColorBox[]{Code}{o}% +{colback=codebackground, colframe=codeborder, + fontupper=\\footnotesize\\setlength{\\fboxsep}{0pt}, + colupper=EFD, + IfNoValueTF={#1}% + {boxsep=2pt, arc=2.5pt, outer arc=2.5pt, + boxrule=0.5pt, left=2pt}% + {boxsep=2.5pt, arc=0pt, outer arc=0pt, + boxrule=0pt, leftrule=1.5pt, left=0.5pt}, + right=2pt, top=1pt, bottom=0.5pt, + breakable}" + "Preamble content injected when using engrave-faces-latex for source blocks. +This is relevant when `org-latex-listings' is set to `engraved'. + +There is quite a lot of flexibility in what this preamble can be, as long as it: +- Loads the fvextra package. +- Loads the package xcolor (if it is not already loader elsewhere). +- Defines a \"Code\" environment (note the capital C), which all + \"Verbatim\" environments (provided by fvextra) will be wrapped with. + +A macro-like placeholder is used to set fvextra's defaults according to +`org-latex-engraved-options': + + [FVEXTRA-SETUP] + +In the default value the color \"EFD\" is provided as this is the +foreground colour provided by engrave-faces-latex. When there +are example/fixed-width blocks only, the engraved generated +preamble is not included, and so it is provided so we may use it +anyway." + :group 'org-export-latex + :type 'string + :package-version '(Org . "9.6")) + +(defcustom org-latex-engraved-options + '(("commandchars" . "\\\\\\{\\}") + ("highlightcolor" . "white!95!black!80!blue") + ("breaklines" . "true") + ("breaksymbol" . "\\color{white!60!black}\\tiny\\ensuremath{\\hookrightarrow}")) + "Association list of options for the latex fvextra package when engraving code. + +These options are set using \\fvset{...} in the preamble of the +LaTeX export. Each element of the alist should be a list or cons +cell containing two strings: the name of the option, and the +value. For example, + + (setq org-latex-engraved-options + \\='((\"highlightcolor\" \"green\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-engraved-options + \\='((\"highlightcolor\" . \"green\") (\"frame\" . \"lines\"))) + +will result in the following LaTeX in the preamble + +\\fvset{% + bgcolor=bg, + frame=lines} + +This will affect all fvextra environments. Note that the same +options will be applied to all blocks. If you need +block-specific options, you may use the following syntax: + + #+ATTR_LATEX: :options key1=value1,key2=value2 + #+BEGIN_SRC <LANG> + ... + #+END_SRC" + :group 'org-export-latex + :type '(alist :key-type (string :tag "option") + :value-type (string :tag "value"))) + +(defun org-latex-generate-engraved-preamble (info syntax-colours-p) + "Generate the preamble to setup engraved code. +The result is constructed from the :latex-engraved-preamble and +:latex-engraved-optionsn export options, the default values of +which are given by `org-latex-engraved-preamble' and +`org-latex-engraved-options' respectively." + (let* ((engraved-options + (plist-get info :latex-engraved-options)) + (engraved-preamble-template + (plist-get info :latex-engraved-preamble)) + (engraved-preamble + (if (string-match "^[ \t]*\\[FVEXTRA-SETUP\\][ \t]*\n?" + engraved-preamble-template) + (replace-match + (concat + "\\fvset{%\n " + (org-latex--make-option-string engraved-options ",\n ") + "}\n") + t t + engraved-preamble-template) + engraved-preamble-template))) + (if syntax-colours-p + (concat + "\n% Setup for code blocks [1/2]\n\n" + engraved-preamble + "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n" + (if (require 'engrave-faces-latex nil t) + (engrave-faces-latex-gen-preamble) + (message "Cannot engrave source blocks. Consider installing `engrave-faces'.") + "% WARNING syntax highlighting unavailible as engrave-faces-latex was missing.\n") + "\n") + (concat + "\n% Setup for code blocks\n\n" + engraved-preamble + "\n")))) ;;;; Compilation @@ -1756,6 +1908,17 @@ (defun org-latex-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template spec))) + ;; engrave-faces-latex preamble + (when (eq org-latex-listings 'engraved) + (let ((src-p (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity + info t)) + (fixedw-p + (org-element-map (plist-get info :parse-tree) + '(example-block fixed-width) #'identity + info t))) + (when (or src-p fixedw-p) + (org-latex-generate-engraved-preamble info src-p)))) ;; Document start. "\\begin{document}\n\n" ;; Title command. @@ -2142,6 +2305,7 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) (pcase (plist-get info :latex-listings) ('nil (org-latex--text-markup code 'code info)) ('minted (org-latex-inline-src-block--minted info code lang)) + ('engraved (org-latex-inline-src-block--engraved info code lang)) (_ (org-latex-inline-src-block--listings info code lang))))) (defun org-latex-inline-src-block--minted (info code lang) @@ -2157,6 +2321,24 @@ (defun org-latex-inline-src-block--minted (info code lang) mint-lang code))) +(defun org-latex-inline-src-block--engraved (_info code lang) + "Transcode an inline src block's content from Org to LaTeX, using engrave-faces. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (if (require 'engrave-faces-latex nil t) + (let (engraved-buffer engraved-code) + (setq engraved-buffer + (with-temp-buffer + (insert code) + (funcall (org-src-get-lang-mode lang)) + (engrave-faces-latex-buffer))) + (setq engraved-code + (with-current-buffer engraved-buffer + (buffer-string))) + (kill-buffer engraved-buffer) + (format "\\Verb{%s}" + engraved-code)) + (user-error "Cannot engrave inline src block, `engrave-faces-latex' is unavailible."))) + (defun org-latex-inline-src-block--listings (info code lang) "Transcode an inline src block's content from Org to LaTeX, using lstlistings. INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." @@ -3017,6 +3199,9 @@ (defun org-latex-src-block (src-block _contents info) num-start retain-labels attributes float custom-env)) ((eq listings 'minted) (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) + ((eq listings 'engraved) + (org-latex-src-block--engraved src-block info lang caption caption-above-p label num-start retain-labels attributes float)) (t (org-latex-src-block--listings src-block info lang caption caption-above-p label @@ -3133,6 +3318,79 @@ (defun org-latex-src-block--minted ;; Return value. (format float-env body))) +(defun org-latex-src-block--engraved + (src-block info lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using engrave-faces-latex. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (if (require 'engrave-faces-latex nil t) + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-engraved-options)) + (content-buffer + (with-temp-buffer + (insert + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))) + (funcall (org-src-get-lang-mode lang)) + (engrave-faces-latex-buffer))) + (content + (with-current-buffer content-buffer + (buffer-string))) + (body + (format + "\\begin{Code}\n\\begin{Verbatim}[%s]\n%s\\end{Verbatim}\n\\end{Code}" + ;; Options. + (concat + (org-latex--make-option-string + (append + (when (and num-start (not (assoc "linenos" options))) + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (list local-options)))))) + content))) + (kill-buffer content-buffer) + ;; Return value. + (format float-env body)) + (user-error "Cannot engrave src block, `engrave-faces-latex' is unavailible."))) + (defun org-latex-src-block--listings (src-block info lang caption caption-above-p label num-start retain-labels attributes float) -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: 0005-ox-latex-Don-t-use-length-to-get-string-width.patch --] [-- Type: text/x-patch, Size: 2005 bytes --] From 531a8bdd52bc6c9b7ba0da847809c76f14221bb1 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sat, 7 May 2022 13:59:13 +0800 Subject: [PATCH 5/7] ox-latex: Don't use `length' to get string width * lisp/ox-latex.el (org-latex-src-block--listings, org-latex-src-block--engraved, org-latex-src-block--minted): Use `string-width' instead of `length' to gauge the displayed width of the string in LaTeX. This may not be a perfect match, but it should be an improvement. --- lisp/ox-latex.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index b9c6d4c3e..6a794c41c 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -3299,7 +3299,7 @@ (defun org-latex-src-block--minted (let* ((code-info (org-export-unravel-code src-block)) (max-width (apply 'max - (mapcar 'length + (mapcar 'string-width (org-split-string (car code-info) "\n"))))) (org-export-format-code @@ -3352,7 +3352,7 @@ (defun org-latex-src-block--engraved (let* ((code-info (org-export-unravel-code src-block)) (max-width (apply 'max - (mapcar 'length + (mapcar 'string-width (org-split-string (car code-info) "\n"))))) (org-export-format-code @@ -3442,7 +3442,7 @@ (defun org-latex-src-block--listings (let* ((code-info (org-export-unravel-code src-block)) (max-width (apply 'max - (mapcar 'length + (mapcar 'string-width (org-split-string (car code-info) "\n"))))) (org-export-format-code (car code-info) -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #7: 0006-ox-latex-Refactor-source-block-transcode-fun-sigs.patch --] [-- Type: text/x-patch, Size: 7091 bytes --] From 1961039336917e6f4e3698aadccc03444dfc2592 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sat, 7 May 2022 14:02:44 +0800 Subject: [PATCH 6/7] ox-latex: Refactor source block transcode fun sigs * lisp/ox-latex.el (org-latex-src-block--listings, org-latex-src-block--engraved, org-latex-src-block--minted, org-latex-src-block--custom): Refactor these --backend functions to use cl-defun with keys instead of having an 11-argument signature. (org-latex-src-block): Adjust for the change in signature of the --backend functions, and refactor the `cond' statement to use `pcase'. --- lisp/ox-latex.el | 78 +++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 6a794c41c..685899c7d 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -3179,37 +3179,37 @@ (defun org-latex-src-block (src-block _contents info) contextual information." (when (org-string-nw-p (org-element-property :value src-block)) (let* ((lang (org-element-property :language src-block)) - (caption (org-element-property :caption src-block)) - (caption-above-p (org-latex--caption-above-p src-block info)) - (label (org-element-property :name src-block)) - (custom-env (and lang - (cadr (assq (intern lang) - org-latex-custom-lang-environments)))) - (num-start (org-export-get-loc src-block info)) - (retain-labels (org-element-property :retain-labels src-block)) - (attributes (org-export-read-attribute :attr_latex src-block)) - (float (plist-get attributes :float)) - (listings (plist-get info :latex-listings))) - (cond - ((or (not lang) (not listings)) - (org-latex-src-block--verbatim src-block info lang caption caption-above-p label - num-start retain-labels attributes float)) - (custom-env - (org-latex-src-block--custom src-block info lang caption caption-above-p label - num-start retain-labels attributes float custom-env)) - ((eq listings 'minted) - (org-latex-src-block--minted src-block info lang caption caption-above-p label - num-start retain-labels attributes float)) - ((eq listings 'engraved) - (org-latex-src-block--engraved src-block info lang caption caption-above-p label - num-start retain-labels attributes float)) - (t - (org-latex-src-block--listings src-block info lang caption caption-above-p label - num-start retain-labels attributes float)))))) - -(defun org-latex-src-block--verbatim - (src-block info _lang caption caption-above-p _label - _num-start _retain-labels _attributes float) + (caption (org-element-property :caption src-block)) + (caption-above-p (org-latex--caption-above-p src-block info)) + (label (org-element-property :name src-block)) + (custom-env (and lang + (cadr (assq (intern lang) + org-latex-custom-lang-environments)))) + (num-start (org-export-get-loc src-block info)) + (retain-labels (org-element-property :retain-labels src-block)) + (attributes (org-export-read-attribute :attr_latex src-block)) + (float (plist-get attributes :float)) + (listings (plist-get info :latex-listings))) + (funcall + (pcase listings + ((or (pred not) (guard (not lang))) #'org-latex-src-block--verbatim + ((guard custom-env) #'org-latex-src-block--custom) + ('minted #'org-latex-src-block--minted) + ('engraved #'org-latex-src-block--engraved) + (_ #'org-latex-src-block--listings))) + :src-block src-block + :info info + :lang lang + :caption caption + :caption-above-p caption-above-p + :label label + :num-start num-start + :retain-labels retain-labels + :attributes attributes + :float float)))) + +(cl-defun org-latex-src-block--verbatim + (&key src-block info caption caption-above-p float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using verbatim. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3228,9 +3228,8 @@ (defun org-latex-src-block--verbatim (if caption-above-p "" (concat "\n" caption-str)))) (t verbatim)))) -(defun org-latex-src-block--custom - (src-block info _lang caption caption-above-p _label - _num-start _retain-labels attributes float custom-env) +(cl-defun org-latex-src-block--custom + (&key src-block info caption caption-above-p attributes float custom-env &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using a custom environment. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3251,8 +3250,7 @@ (defun org-latex-src-block--custom (?o . ,(or (plist-get attributes :options) ""))))))) (defun org-latex-src-block--minted - (src-block info lang caption caption-above-p _label - num-start retain-labels attributes float) + (&key src-block info lang caption caption-above-p num-start retain-labels attributes float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using minted. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3319,8 +3317,7 @@ (defun org-latex-src-block--minted (format float-env body))) (defun org-latex-src-block--engraved - (src-block info lang caption caption-above-p _label - num-start retain-labels attributes float) + (&key src-block info lang caption caption-above-p num-start retain-labels attributes float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using engrave-faces-latex. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3391,9 +3388,8 @@ (defun org-latex-src-block--engraved (format float-env body)) (user-error "Cannot engrave src block, `engrave-faces-latex' is unavailible."))) -(defun org-latex-src-block--listings - (src-block info lang caption caption-above-p label - num-start retain-labels attributes float) +(cl-defun org-latex-src-block--listings + (&key src-block info lang caption caption-above-p label num-start retain-labels attributes float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using listings. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #8: 0007-ox-latex-Replace-org-latex-listings.patch --] [-- Type: text/x-patch, Size: 16140 bytes --] From 4d24b74e5490a30c75c7a23721c836a8ce4756b6 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sat, 7 May 2022 14:46:28 +0800 Subject: [PATCH 7/7] ox-latex: Replace `org-latex-listings' * lisp/ox-latex.el (org-latex-src-block, org-latex-keyword, org-latex-inline-src-block, org-latex-template, org-latex--caption/label-string, org-latex-engraved-preamble, org-latex-listings): Replace `org-latex-listings' with `org-latex-src-block-backend', which now can be set to listings/verbatim and no longer advertises t/nil as valid values. * lisp/ox-beamer.el (org-beamer-template): Update in the same manner as `org-latex-template'. * lisp/org-compat.el: Make `org-latex-listings' an obsolete alias for `org-latex-src-block-backend'. * testing/lisp/test-ox.el: Replace `org-latex-listings' reference with `org-latex-src-block-backend'. * doc/org-manual.org (Footnotes, LaTeX specific properties, Literal Examples): Replace references to `org-latex-listings' with `org-latex-src-block-backend'. * etc/ORG-NEWS: Add a news entry noting this change. The variable `org-latex-listings' originally indicated whether source blocks should use the listings LaTeX package, or not. This usage has evolved over the years, and now it sets one of four different fontification backends. This renaming should make the variable name a bit less misleading. --- doc/org-manual.org | 6 +-- etc/ORG-NEWS | 9 ++++ lisp/org-compat.el | 2 + lisp/ox-beamer.el | 2 +- lisp/ox-latex.el | 111 ++++++++++++++++++++++------------------ testing/lisp/test-ox.el | 2 +- 6 files changed, 78 insertions(+), 54 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index c0d38cd8c..60bded419 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -11159,7 +11159,7 @@ ** Literal Examples #+end_example #+cindex: formatting source code, markup rules -#+vindex: org-latex-listings +#+vindex: org-latex-src-block-backend If the example is source code from a programming language, or any other text that can be marked up by Font Lock in Emacs, you can ask for the example to look like the fontified Emacs buffer[fn:114]. This @@ -16304,12 +16304,12 @@ **** LaTeX specific properties | ~:latex-link-with-unknown-path-format~ | ~org-latex-link-with-unknown-path-format~ | | ~:latex-listings-langs~ | ~org-latex-listings-langs~ | | ~:latex-listings-options~ | ~org-latex-listings-options~ | -| ~:latex-listings~ | ~org-latex-listings~ | | ~:latex-minted-langs~ | ~org-latex-minted-langs~ | | ~:latex-minted-options~ | ~org-latex-minted-options~ | | ~:latex-prefer-user-labels~ | ~org-latex-prefer-user-labels~ | | ~:latex-subtitle-format~ | ~org-latex-subtitle-format~ | | ~:latex-subtitle-separate~ | ~org-latex-subtitle-separate~ | +| ~:latex-src-block-backend~ | ~org-latex-src-block-backend~ | | ~:latex-table-scientific-notation~ | ~org-latex-table-scientific-notation~ | | ~:latex-tables-booktabs~ | ~org-latex-tables-booktabs~ | | ~:latex-tables-centered~ | ~org-latex-tables-centered~ | @@ -22256,7 +22256,7 @@ * Footnotes version 1.34 of the =htmlize.el= package, which you need to install). Fontified code chunks in LaTeX can be achieved using either the [[https://www.ctan.org/pkg/listings][listings]] package or the [[https://www.ctan.org/pkg/minted][minted]] package. Refer to -~org-latex-listings~ for details. +~org-latex-src-block-backend~ for details. [fn:115] Source code in code blocks may also be evaluated either interactively or on export. See [[*Working with Source Code]] for more diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 1e8558c7b..c5f0bcb33 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -268,6 +268,15 @@ Chmod-style permissions are based on the new variable ~org-babel-tangle-default-file-mode~. *** A new custom setting =org-agenda-clock-report-header= to add a header to org agenda clock report + +*** ~org-latex-listings~ has been replaced with ~org-latex-src-block-backend~ + +~org-latex-listings~ has been renamed to better reflect the current +purpose of the variable. The replacement variable +~org-latex-src-block-backend~ acts in exactly the same way, however it +accepts =listings= and =verbatim= in place of =t= and =nil= (which +still work, but are no longer listed as valid options). + * Version 9.5 ** Important announcements and breaking changes diff --git a/lisp/org-compat.el b/lisp/org-compat.el index f599e246e..c1a78e834 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -324,6 +324,8 @@ (define-obsolete-variable-alias 'org-latex-create-formula-image-program 'org-preview-latex-default-process "9.0") (define-obsolete-variable-alias 'org-latex-preview-ltxpng-directory 'org-preview-latex-image-directory "9.0") +(define-obsolete-variable-alias 'org-latex-listings + 'org-latex-src-block-backend "9.6") (define-obsolete-function-alias 'org-table-p 'org-at-table-p "9.0") (define-obsolete-function-alias 'org-on-heading-p 'org-at-heading-p "9.0") (define-obsolete-function-alias 'org-at-regexp-p 'org-in-regexp "8.3") diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 4d40f6a1d..3baa4e26e 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -858,7 +858,7 @@ (defun org-beamer-template (contents info) (and (stringp template) (format-spec template (org-latex--format-spec info)))) ;; engrave-faces-latex preamble - (when (eq org-latex-listings 'engraved) + (when (eq org-latex-src-block-backend 'engraved) (let ((src-p (org-element-map (plist-get info :parse-tree) '(src-block inline-src-block) #'identity info t)) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 685899c7d..8f4206164 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -143,7 +143,7 @@ (org-export-define-backend 'latex (:latex-inactive-timestamp-format nil nil org-latex-inactive-timestamp-format) (:latex-inline-image-rules nil nil org-latex-inline-image-rules) (:latex-link-with-unknown-path-format nil nil org-latex-link-with-unknown-path-format) - (:latex-listings nil nil org-latex-listings) + (:latex-src-block-backend nil nil org-latex-src-block-backend) (:latex-listings-langs nil nil org-latex-listings-langs) (:latex-listings-options nil nil org-latex-listings-options) (:latex-minted-langs nil nil org-latex-minted-langs) @@ -937,22 +937,22 @@ (defcustom org-latex-format-inlinetask-function ;; Src blocks -(defcustom org-latex-listings nil - "Non-nil means export source code using the listings package. +(defcustom org-latex-src-block-backend 'verbatim + "Backend used to generate source code listings. -This package will fontify source code, possibly even with color. -There are four implementations of this functionality you may +This sets the behaviour for fontifying source code, possibly even with +color. There are four implementations of this functionality you may choose from (ordered from least to most capable): -1. Verbatim (nil) -2. Listings (t) -3. Minted (minted) -4. Engraved (engraved) +1. Verbatim +2. Listings +3. Minted +4. Engraved The first two options provide basic syntax highlighting (listings), or none at all (verbatim). -When using listings, you also need to make use of the LaTeX -\"listings\" package. The \"color\" package is also needed if you +When using listings, you also need to make use of LaTeX package +\"listings\"e. The \"color\" LaTeX package is also needed if you would like color too. These can simply be added to `org-latex-packages-alist', using customise or something like: @@ -963,27 +963,12 @@ (defcustom org-latex-listings nil There are two further options for more comprehensive fontification. The first can be set with, - (setq org-latex-listings \\='engraved) + (setq org-latex-src-block-backend \\='minted) -which causes source code to be run through -`engrave-faces-latex-buffer', which generates colorings using -Emacs' font-lock information. This requires the engrave-faces -package (availible from ELPA), and the fvextra LaTeX package be -installed. - -The styling of the engraved result can customised with -`org-latex-engraved-preamble' and `org-latex-engraved-options'. -The default preamble also uses the tcolorbox LaTeX package in -addition to fvextra. - -The second more comprehensive option can be set with, - - (setq org-latex-listings \\='minted) - -which causes source code to be exported using the minted package -as opposed to listings. If you want to use minted, you need to -add the minted package to `org-latex-packages-alist', for example -using customize, or with +which causes source code to be exported using the LaTeX package +minted as opposed to listings. If you want to use minted, you +need to add the minted package to `org-latex-packages-alist', for +example using customize, or with (require \\='ox-latex) (add-to-list \\='org-latex-packages-alist \\='(\"newfloat\" \"minted\")) @@ -996,14 +981,29 @@ (defcustom org-latex-listings nil The minted choice has possible repercussions on the preview of latex fragments (see `org-preview-latex-fragment'). If you run into previewing problems, please consult -URL `https://orgmode.org/worg/org-tutorials/org-latex-preview.html'." +URL `https://orgmode.org/worg/org-tutorials/org-latex-preview.html'. + +The most comprehensive option can be set with, + + (setq org-latex-src-block-backend \\='engraved) + +which causes source code to be run through +`engrave-faces-latex-buffer', which generates colorings using +Emacs' font-lock information. This requires the Emacs package +engrave-faces (availible from ELPA), and the LaTeX package +fvextra be installed. + +The styling of the engraved result can customised with +`org-latex-engraved-preamble' and `org-latex-engraved-options'. +The default preamble also uses the LaTeX package tcolorbox in +addition to fvextra." :group 'org-export-latex :type '(choice - (const :tag "Use listings" t) + (const :tag "Use listings" listings) (const :tag "Use minted" minted) (const :tag "Use engrave-faces-latex" engraved) - (const :tag "Export verbatim" nil)) - :safe (lambda (s) (memq s '(t nil minted engraved)))) + (const :tag "Export verbatim" verbatim)) + :safe (lambda (s) (memq s '(listings minted engraved verbatim)))) (defcustom org-latex-listings-langs '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp") @@ -1201,7 +1201,7 @@ (defcustom org-latex-engraved-preamble right=2pt, top=1pt, bottom=0.5pt, breakable}" "Preamble content injected when using engrave-faces-latex for source blocks. -This is relevant when `org-latex-listings' is set to `engraved'. +This is relevant when `org-latex-src-block-backend' is set to `engraved'. There is quite a lot of flexibility in what this preamble can be, as long as it: - Loads the fvextra package. @@ -1502,7 +1502,8 @@ (defun org-latex--caption/label-string (element info) main) (and (eq type 'src-block) (not (plist-get attr :float)) - (null (plist-get info :latex-listings))))) + (memq (plist-get info :latex-src-block-backend) + '(verbatim nil))))) (short (org-export-get-caption element t)) (caption-from-attr-latex (plist-get attr :caption))) (cond @@ -1522,7 +1523,8 @@ (defun org-latex--caption/label-string (element info) (paragraph "figure") (image "figure") (special-block "figure") - (src-block (if (plist-get info :latex-listings) + (src-block (if (not (memq (plist-get info :latex-src-block-backend) + '(verbatim nil))) "listing" "figure")) (t (symbol-name type*))) @@ -1909,7 +1911,7 @@ (defun org-latex-template (contents info) (and (stringp template) (format-spec template spec))) ;; engrave-faces-latex preamble - (when (eq org-latex-listings 'engraved) + (when (eq org-latex-src-block-backend 'engraved) (let ((src-p (org-element-map (plist-get info :parse-tree) '(src-block inline-src-block) #'identity info t)) @@ -2302,11 +2304,17 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) contextual information." (let ((code (org-element-property :value inline-src-block)) (lang (org-element-property :language inline-src-block))) - (pcase (plist-get info :latex-listings) - ('nil (org-latex--text-markup code 'code info)) + (pcase (plist-get info :latex-src-block-backend) + ('verbatim (org-latex--text-markup code 'code info)) ('minted (org-latex-inline-src-block--minted info code lang)) ('engraved (org-latex-inline-src-block--engraved info code lang)) - (_ (org-latex-inline-src-block--listings info code lang))))) + ('listings (org-latex-inline-src-block--listings info code lang)) + (oldval + (message "Please update the LaTeX src-block-backend to %s" + (if oldval "listings" "verbatim")) + (if oldval + (org-latex-inline-src-block--listings info code lang) + (org-latex--text-markup code 'code info)))))) (defun org-latex-inline-src-block--minted (info code lang) "Transcode an inline src block's content from Org to LaTeX, using minted. @@ -2502,7 +2510,7 @@ (defun org-latex-keyword (keyword _contents info) (concat depth (and depth "\n") "\\tableofcontents")))) ((string-match-p "\\<tables\\>" value) "\\listoftables") ((string-match-p "\\<listings\\>" value) - (cl-case (plist-get info :latex-listings) + (cl-case (plist-get info :latex-src-block-backend) ((nil) "\\listoffigures") (minted "\\listoflistings") (otherwise "\\lstlistoflistings"))))))))) @@ -3188,15 +3196,20 @@ (defun org-latex-src-block (src-block _contents info) (num-start (org-export-get-loc src-block info)) (retain-labels (org-element-property :retain-labels src-block)) (attributes (org-export-read-attribute :attr_latex src-block)) - (float (plist-get attributes :float)) - (listings (plist-get info :latex-listings))) + (float (plist-get attributes :float))) (funcall - (pcase listings - ((or (pred not) (guard (not lang))) #'org-latex-src-block--verbatim - ((guard custom-env) #'org-latex-src-block--custom) + (pcase (plist-get info :latex-src-block-backend) + ((or 'verbatim (guard (not lang))) #'org-latex-src-block--verbatim ('minted #'org-latex-src-block--minted) ('engraved #'org-latex-src-block--engraved) - (_ #'org-latex-src-block--listings))) + ('listings #'org-latex-src-block--listings) + ((guard custom-env) #'org-latex-src-block--custom) + (oldval + (message "Please update the LaTeX src-block-backend to %s" + (if oldval "listings" "verbatim")) + (if oldval + #'org-latex-src-block--listings + #'org-latex-src-block--verbatim)))) :src-block src-block :info info :lang lang diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el index 25e02b258..28f950813 100644 --- a/testing/lisp/test-ox.el +++ b/testing/lisp/test-ox.el @@ -3978,7 +3978,7 @@ (ert-deftest test-org-export/latex-src-block-verbatim-caption () \\end{verbatim} \\caption{Caption is below, 60\\%s} \\end{figure*}" - (let ((org-latex-listings 'minted) ; inactive due to missing lang + (let ((org-latex-src-block-backend 'minted) ; inactive due to missing lang (org-latex-default-figure-position "tp")) ;; Namely "multicolumn" value to get just figure environment ;; looks like a bug. -- 2.35.3 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-07 6:57 ` Timothy @ 2022-05-07 10:40 ` Timothy 2022-05-07 11:33 ` Daniel Fleischer 0 siblings, 1 reply; 27+ messages in thread From: Timothy @ 2022-05-07 10:40 UTC (permalink / raw) To: Ihor Radchenko; +Cc: emacs-orgmode, Daniel Fleischer, Nicolas Goaziou [-- Attachment #1: Type: text/plain, Size: 131 bytes --] Ooops, a paren error managed to slip in there. Here’s a new set, with a little extra refactoring slipped in. – Timothy [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-ox-latex-Refactor-org-latex-src-block.patch --] [-- Type: text/x-patch, Size: 15942 bytes --] From d231437e2c9f96bf70520d9ddda810a95667fcdd Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 14:35:34 +0800 Subject: [PATCH 1/7] ox-latex: Refactor `org-latex-src-block' * lisp/ox-latex.el (org-latex-src-block): Extract the per-format logic from `org-latex-src-block' into new dedicated functions: + `org-latex-src-block--verbatim' + `org-latex-src-block--custom' + `org-latex-src-block--minted' + `org-latex-src-block--listings' This makes `org-latex-src-block' much less monolithic, taking it from 175 lines to 30, and I find also makes it easier to understand. --- lisp/ox-latex.el | 339 ++++++++++++++++++++++++++--------------------- 1 file changed, 185 insertions(+), 154 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 841ad48bc..c2f728a1c 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2997,164 +2997,195 @@ (defun org-latex-src-block (src-block _contents info) (float (plist-get attributes :float)) (listings (plist-get info :latex-listings))) (cond - ;; Case 1. No source fontification. ((or (not lang) (not listings)) - (let ((caption-str (org-latex--caption/label-string src-block info)) - (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" - (org-export-format-code-default src-block info)))) - (cond ((string= "multicolumn" float) - (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" - (plist-get info :latex-default-figure-position) - (if caption-above-p caption-str "") - verbatim - (if caption-above-p "" caption-str))) - (caption (concat - (if caption-above-p caption-str "") - verbatim - (if caption-above-p "" (concat "\n" caption-str)))) - (t verbatim)))) - ;; Case 2. Custom environment. + (org-latex-src-block--verbatim src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) (custom-env - (let ((caption-str (org-latex--caption/label-string src-block info)) - (formatted-src (org-export-format-code-default src-block info))) - (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) - (format "\\begin{%s}\n%s\\end{%s}\n" - custom-env - (concat (and caption-above-p caption-str) - formatted-src - (and (not caption-above-p) caption-str)) - custom-env) - (format-spec custom-env - `((?s . ,formatted-src) - (?c . ,caption) - (?f . ,float) - (?l . ,(org-latex--label src-block info)) - (?o . ,(or (plist-get attributes :options) ""))))))) - ;; Case 3. Use minted package. + (org-latex-src-block--custom src-block info lang caption caption-above-p label + num-start retain-labels attributes float custom-env)) ((eq listings 'minted) - (let* ((caption-str (org-latex--caption/label-string src-block info)) - (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) - (plist-get info :latex-default-figure-position))) - (float-env - (cond - ((string= "multicolumn" float) - (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - (caption - (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - ((string= "t" float) - (concat (format "\\begin{listing}[%s]\n" - placement) - "%s\n\\end{listing}")) - (t "%s"))) - (options (plist-get info :latex-minted-options)) - (body - (format - "\\begin{minted}[%s]{%s}\n%s\\end{minted}" - ;; Options. - (concat - (org-latex--make-option-string - (if (or (not num-start) (assoc "linenos" options)) - options - (append - `(("linenos") - ("firstnumber" ,(number-to-string (1+ num-start)))) - options))) - (let ((local-options (plist-get attributes :options))) - (and local-options (concat "," local-options)))) - ;; Language. - (or (cadr (assq (intern lang) - (plist-get info :latex-minted-langs))) - (downcase lang)) - ;; Source code. - (let* ((code-info (org-export-unravel-code src-block)) - (max-width - (apply 'max - (mapcar 'length - (org-split-string (car code-info) - "\n"))))) - (org-export-format-code - (car code-info) - (lambda (loc _num ref) - (concat - loc - (when ref - ;; Ensure references are flushed to the right, - ;; separated with 6 spaces from the widest line - ;; of code. - (concat (make-string (+ (- max-width (length loc)) 6) - ?\s) - (format "(%s)" ref))))) - nil (and retain-labels (cdr code-info))))))) - ;; Return value. - (format float-env body))) - ;; Case 4. Use listings package. + (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) (t - (let ((lst-lang - (or (cadr (assq (intern lang) - (plist-get info :latex-listings-langs))) - lang)) - (caption-str - (when caption - (let ((main (org-export-get-caption src-block)) - (secondary (org-export-get-caption src-block t))) - (if (not secondary) - (format "{%s}" (org-export-data main info)) - (format "{[%s]%s}" - (org-export-data secondary info) - (org-export-data main info)))))) - (lst-opt (plist-get info :latex-listings-options))) - (concat - ;; Options. - (format - "\\lstset{%s}\n" - (concat - (org-latex--make-option-string - (append - lst-opt - (cond - ((and (not float) (plist-member attributes :float)) nil) - ((string= "multicolumn" float) '(("float" "*"))) - ((and float (not (assoc "float" lst-opt))) - `(("float" ,(plist-get info :latex-default-figure-position))))) - `(("language" ,lst-lang)) - (if label - `(("label" ,(org-latex--label src-block info))) - '(("label" " "))) - (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) - `(("captionpos" ,(if caption-above-p "t" "b"))) - (cond ((assoc "numbers" lst-opt) nil) - ((not num-start) '(("numbers" "none"))) - (t `(("firstnumber" ,(number-to-string (1+ num-start))) - ("numbers" "left")))))) - (let ((local-options (plist-get attributes :options))) - (and local-options (concat "," local-options))))) - ;; Source code. - (format - "\\begin{lstlisting}\n%s\\end{lstlisting}" - (let* ((code-info (org-export-unravel-code src-block)) - (max-width - (apply 'max - (mapcar 'length - (org-split-string (car code-info) "\n"))))) - (org-export-format-code - (car code-info) - (lambda (loc _num ref) - (concat - loc - (when ref - ;; Ensure references are flushed to the right, - ;; separated with 6 spaces from the widest line of - ;; code - (concat (make-string (+ (- max-width (length loc)) 6) ?\s) - (format "(%s)" ref))))) - nil (and retain-labels (cdr code-info)))))))))))) - + (org-latex-src-block--listings src-block info lang caption caption-above-p label + num-start retain-labels attributes float)))))) + +(defun org-latex-src-block--verbatim + (src-block info _lang caption caption-above-p _label + _num-start _retain-labels _attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using verbatim. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((caption-str (org-latex--caption/label-string src-block info)) + (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" + (org-export-format-code-default src-block info)))) + (cond ((string= "multicolumn" float) + (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" + (plist-get info :latex-default-figure-position) + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" caption-str))) + (caption (concat + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" (concat "\n" caption-str)))) + (t verbatim)))) + +(defun org-latex-src-block--custom + (src-block info _lang caption caption-above-p _label + _num-start _retain-labels attributes float custom-env) + "Transcode a SRC-BLOCK element from Org to LaTeX, using a custom environment. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((caption-str (org-latex--caption/label-string src-block info)) + (formatted-src (org-export-format-code-default src-block info))) + (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) + (format "\\begin{%s}\n%s\\end{%s}\n" + custom-env + (concat (and caption-above-p caption-str) + formatted-src + (and (not caption-above-p) caption-str)) + custom-env) + (format-spec custom-env + `((?s . ,formatted-src) + (?c . ,caption) + (?f . ,float) + (?l . ,(org-latex--label src-block info)) + (?o . ,(or (plist-get attributes :options) ""))))))) + +(defun org-latex-src-block--minted + (src-block info lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using minted. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-minted-options)) + (body + (format + "\\begin{minted}[%s]{%s}\n%s\\end{minted}" + ;; Options. + (concat + (org-latex--make-option-string + (if (or (not num-start) (assoc "linenos" options)) + options + (append + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start)))) + options))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options)))) + ;; Language. + (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase lang)) + ;; Source code. + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))))) + ;; Return value. + (format float-env body))) + +(defun org-latex-src-block--listings + (src-block info lang caption caption-above-p label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using listings. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((lst-lang + (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + lang)) + (caption-str + (when caption + (let ((main (org-export-get-caption src-block)) + (secondary (org-export-get-caption src-block t))) + (if (not secondary) + (format "{%s}" (org-export-data main info)) + (format "{[%s]%s}" + (org-export-data secondary info) + (org-export-data main info)))))) + (lst-opt (plist-get info :latex-listings-options))) + (concat + ;; Options. + (format + "\\lstset{%s}\n" + (concat + (org-latex--make-option-string + (append + lst-opt + (cond + ((and (not float) (plist-member attributes :float)) nil) + ((string= "multicolumn" float) '(("float" "*"))) + ((and float (not (assoc "float" lst-opt))) + `(("float" ,(plist-get info :latex-default-figure-position))))) + `(("language" ,lst-lang)) + (if label + `(("label" ,(org-latex--label src-block info))) + '(("label" " "))) + (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) + `(("captionpos" ,(if caption-above-p "t" "b"))) + (cond ((assoc "numbers" lst-opt) nil) + ((not num-start) '(("numbers" "none"))) + (t `(("firstnumber" ,(number-to-string (1+ num-start))) + ("numbers" "left")))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options))))) + ;; Source code. + (format + "\\begin{lstlisting}\n%s\\end{lstlisting}" + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line of + ;; code + (concat (make-string (+ (- max-width (length loc)) 6) ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info)))))))) ;;;; Statistics Cookie -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-ox-latex-Refactor-org-latex-inline-src-block.patch --] [-- Type: text/x-patch, Size: 4016 bytes --] From aa8406ce64507b870322495e8f9b54317930ed24 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 4 May 2022 18:53:10 +0800 Subject: [PATCH 2/7] ox-latex: Refactor `org-latex-inline-src-block' * lisp/ox-latex.el (org-latex-inline-src-block, org-latex-inline-src-block--minted, org-latex-inline-src-block--listings): Extract the minted and listings specific logic out of `org-latex-inline-src-block` into the new functions `org-latex-inline-src-block--minted` and `org-latex-inline-src-block--listings`. --- lisp/ox-latex.el | 62 +++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index c2f728a1c..38f36a1f3 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2127,36 +2127,38 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) "Transcode an INLINE-SRC-BLOCK element from Org to LaTeX. CONTENTS holds the contents of the item. INFO is a plist holding contextual information." - (let* ((code (org-element-property :value inline-src-block)) - (separator (org-latex--find-verb-separator code))) - (cl-case (plist-get info :latex-listings) - ;; Do not use a special package: transcode it verbatim, as code. - ((nil) (org-latex--text-markup code 'code info)) - ;; Use minted package. - (minted - (let* ((org-lang (org-element-property :language inline-src-block)) - (mint-lang (or (cadr (assq (intern org-lang) - (plist-get info :latex-minted-langs))) - (downcase org-lang))) - (options (org-latex--make-option-string - (plist-get info :latex-minted-options)))) - (format "\\mintinline%s{%s}{%s}" - (if (string= options "") "" (format "[%s]" options)) - mint-lang - code))) - ;; Use listings package. - (otherwise - ;; Maybe translate language's name. - (let* ((org-lang (org-element-property :language inline-src-block)) - (lst-lang (or (cadr (assq (intern org-lang) - (plist-get info :latex-listings-langs))) - org-lang)) - (options (org-latex--make-option-string - (append (plist-get info :latex-listings-options) - `(("language" ,lst-lang)))))) - (concat (format "\\lstinline[%s]" options) - separator code separator)))))) - + (let ((code (org-element-property :value inline-src-block)) + (lang (org-element-property :language inline-src-block))) + (pcase (plist-get info :latex-listings) + ('nil (org-latex--text-markup code 'code info)) + ('minted (org-latex-inline-src-block--minted info code lang)) + (_ (org-latex-inline-src-block--listings info code lang))))) + +(defun org-latex-inline-src-block--minted (info code lang) + "Transcode an inline src block's content from Org to LaTeX, using minted. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (let ((mint-lang (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase lang))) + (options (org-latex--make-option-string + (plist-get info :latex-minted-options)))) + (format "\\mintinline%s{%s}{%s}" + (if (string= options "") "" (format "[%s]" options)) + mint-lang + code))) + +(defun org-latex-inline-src-block--listings (info code lang) + "Transcode an inline src block's content from Org to LaTeX, using lstlistings. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (let* ((lst-lang (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + lang)) + (separator (org-latex--find-verb-separator code)) + (options (org-latex--make-option-string + (append (plist-get info :latex-listings-options) + `(("language" ,lst-lang)))))) + (concat (format "\\lstinline[%s]" options) + separator code separator))) ;;;; Inlinetask -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-ox-latex-More-versitile-option-construction.patch --] [-- Type: text/x-patch, Size: 4116 bytes --] From 62d6703f0dd622916dff8aab960db6df4cb58cf7 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 4 May 2022 23:31:59 +0800 Subject: [PATCH 3/7] ox-latex: More versitile option construction * lisp/ox-latex.el (org-latex--make-option-string): Support a custom option seperator string. (org-latex--make-option-string, org-latex-minted-options, org-latex-listings-options): The first line of the docstrings for `org-latex-minted-options` and `org-latex-listings-options` describe the variables as "association lists", yet `org-latex--make-option-string` does not handle association lists and an example of two-value lists is provided. To make the behaviour match the docstring, `org-latex--make-option-string` is modified to work with either a list two-value lists or an association list, and the examples in `org-latex-minted-options` and `org-latex-listings-options` updated accordingly. --- lisp/ox-latex.el | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 38f36a1f3..2d4b3bace 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -1006,12 +1006,16 @@ (defcustom org-latex-listings-options nil These options are supplied as a comma-separated list to the \\lstset command. Each element of the association list should be -a list containing two strings: the name of the option, and the -value. For example, +a list or cons cell containing two strings: the name of the +option, and the value. For example, (setq org-latex-listings-options \\='((\"basicstyle\" \"\\\\small\") (\"keywordstyle\" \"\\\\color{black}\\\\bfseries\\\\underbar\"))) + ; or + (setq org-latex-listings-options + \\='((\"basicstyle\" . \"\\\\small\") + (\"keywordstyle\" . \"\\\\color{black}\\\\bfseries\\\\underbar\"))) will typeset the code in a small size font with underlined, bold black keywords. @@ -1059,11 +1063,14 @@ (defcustom org-latex-minted-options nil These options are supplied within square brackets in \\begin{minted} environments. Each element of the alist should -be a list containing two strings: the name of the option, and the -value. For example, +be a list or cons cell containing two strings: the name of the +option, and the value. For example, (setq org-latex-minted-options \\='((\"bgcolor\" \"bg\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-minted-options + \\='((\"bgcolor\" . \"bg\") (\"frame\" . \"lines\"))) will result in source blocks being exported with @@ -1506,21 +1513,24 @@ (defun org-latex--find-verb-separator (s) when (not (string-match (regexp-quote (char-to-string c)) s)) return (char-to-string c)))) -(defun org-latex--make-option-string (options) +(defun org-latex--make-option-string (options &optional seperator) "Return a comma separated string of keywords and values. OPTIONS is an alist where the key is the options keyword as a string, and the value a list containing the keyword value, or nil." (mapconcat (lambda (pair) - (pcase-let ((`(,keyword ,value) pair)) - (concat keyword - (and (> (length value) 0) - (concat "=" - (if (string-match-p (rx (any "[]")) value) - (format "{%s}" value) - value)))))) - options - ",")) + (let ((keyword (car pair)) + (value (pcase (cdr pair) + ((pred stringp) (cdr pair)) + ((pred consp) (cadr pair))))) + (concat keyword + (when value + (concat "=" + (if (string-match-p (rx (any "[]")) value) + (format "{%s}" value) + value)))))) + options + (or seperator ","))) (defun org-latex--wrap-label (element output info) "Wrap label associated to ELEMENT around OUTPUT, if appropriate. -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-ox-latex-Introduce-engraved-code-highlighting.patch --] [-- Type: text/x-patch, Size: 17212 bytes --] From 81155a80fb261812718dcb991fd22f87bb1d5ef6 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 20:04:12 +0800 Subject: [PATCH 4/7] ox-latex: Introduce "engraved" code highlighting * lisp/ox-latex.el (org-latex-src-block, org-latex-src-block--engraved, org-latex-inline-src-block, org-latex-inline-src-block--engraved, org-latex-src--engrave-code, org-latex-template, org-latex-listings): Make use of the engraved-faces package (available on ELPA) to provide an alternative LaTeX code highlighting backend which functions similarly to htmlize.el for HTML exports. (org-latex-engraved-preamble, org-latex-engraved-options): Introduce variables to construct the preamble for engraved code blocks. * lisp/ox-beamer.el (org-beamer-template): Modify to add engrave-faces preamble when applicable. tweak --- lisp/ox-beamer.el | 11 ++ lisp/ox-latex.el | 272 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 274 insertions(+), 9 deletions(-) diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 6be73c91e..4d40f6a1d 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -857,6 +857,17 @@ (defun org-beamer-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template (org-latex--format-spec info)))) + ;; engrave-faces-latex preamble + (when (eq org-latex-listings 'engraved) + (let ((src-p (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity + info t)) + (fixedw-p + (org-element-map (plist-get info :parse-tree) + '(example-block fixed-width) #'identity + info t))) + (when (or src-p fixedw-p) + (org-latex-generate-engraved-preamble info src-p)))) ;; Document start. "\\begin{document}\n\n" ;; Title command. diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 2d4b3bace..10cd6d76d 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -37,6 +37,8 @@ (defvar org-latex-default-packages-alist) (defvar org-latex-packages-alist) (defvar orgtbl-exp-regexp) +(declare-function engrave-faces-latex-gen-preamble "ext:engrave-faces-latex") +(declare-function engrave-faces-latex-buffer "ext:engrave-faces-latex") \f ;;; Define Back-End @@ -125,6 +127,8 @@ (org-export-define-backend 'latex (:latex-default-quote-environment nil nil org-latex-default-quote-environment) (:latex-default-table-mode nil nil org-latex-default-table-mode) (:latex-diary-timestamp-format nil nil org-latex-diary-timestamp-format) + (:latex-engraved-options nil nil org-latex-engraved-options) + (:latex-engraved-preamble nil nil org-latex-engraved-preamble) (:latex-footnote-defined-format nil nil org-latex-footnote-defined-format) (:latex-footnote-separator nil nil org-latex-footnote-separator) (:latex-format-drawer-function nil nil org-latex-format-drawer-function) @@ -937,22 +941,48 @@ (defcustom org-latex-listings nil "Non-nil means export source code using the listings package. This package will fontify source code, possibly even with color. -If you want to use this, you also need to make LaTeX use the -listings package, and if you want to have color, the color -package. Just add these to `org-latex-packages-alist', for -example using customize, or with something like: +There are four implementations of this functionality you may +choose from (ordered from least to most capable): +1. Verbatim (nil) +2. Listings (t) +3. Minted (minted) +4. Engraved (engraved) + +The first two options provide basic syntax +highlighting (listings), or none at all (verbatim). + +When using listings, you also need to make use of the LaTeX +\"listings\" package. The \"color\" package is also needed if you +would like color too. These can simply be added to +`org-latex-packages-alist', using customise or something like: (require \\='ox-latex) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"listings\")) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"color\")) -Alternatively, +There are two further options for more comprehensive +fontification. The first can be set with, + + (setq org-latex-listings \\='engraved) + +which causes source code to be run through +`engrave-faces-latex-buffer', which generates colorings using +Emacs' font-lock information. This requires the engrave-faces +package (availible from ELPA), and the fvextra LaTeX package be +installed. + +The styling of the engraved result can customised with +`org-latex-engraved-preamble' and `org-latex-engraved-options'. +The default preamble also uses the tcolorbox LaTeX package in +addition to fvextra. + +The second more comprehensive option can be set with, (setq org-latex-listings \\='minted) -causes source code to be exported using the minted package as -opposed to listings. If you want to use minted, you need to add -the minted package to `org-latex-packages-alist', for example +which causes source code to be exported using the minted package +as opposed to listings. If you want to use minted, you need to +add the minted package to `org-latex-packages-alist', for example using customize, or with (require \\='ox-latex) @@ -971,8 +1001,9 @@ (defcustom org-latex-listings nil :type '(choice (const :tag "Use listings" t) (const :tag "Use minted" minted) + (const :tag "Use engrave-faces-latex" engraved) (const :tag "Export verbatim" nil)) - :safe (lambda (s) (memq s '(t nil minted)))) + :safe (lambda (s) (memq s '(t nil minted engraved)))) (defcustom org-latex-listings-langs '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp") @@ -1142,6 +1173,127 @@ (defcustom org-latex-custom-lang-environments nil :version "26.1" :package-version '(Org . "9.0")) +(defcustom org-latex-engraved-preamble + "\\usepackage{fvextra} + +[FVEXTRA-SETUP] + +% Make line numbers smaller and grey. +\\renewcommand\\theFancyVerbLine{\\footnotesize\\color{black!40!white}\\arabic{FancyVerbLine}} + +\\usepackage{xcolor} + +\\providecolor{codebackground}{HTML}{f7f7f7} +\\providecolor{codeborder}{HTML}{f0f0f0} +\\providecolor{EFD}{HTML}{28292e} + +% Define a Code environment to prettily wrap the fontified code. +\\usepackage[breakable,xparse]{tcolorbox} +\\DeclareTColorBox[]{Code}{o}% +{colback=codebackground, colframe=codeborder, + fontupper=\\footnotesize\\setlength{\\fboxsep}{0pt}, + colupper=EFD, + IfNoValueTF={#1}% + {boxsep=2pt, arc=2.5pt, outer arc=2.5pt, + boxrule=0.5pt, left=2pt}% + {boxsep=2.5pt, arc=0pt, outer arc=0pt, + boxrule=0pt, leftrule=1.5pt, left=0.5pt}, + right=2pt, top=1pt, bottom=0.5pt, + breakable}" + "Preamble content injected when using engrave-faces-latex for source blocks. +This is relevant when `org-latex-listings' is set to `engraved'. + +There is quite a lot of flexibility in what this preamble can be, as long as it: +- Loads the fvextra package. +- Loads the package xcolor (if it is not already loader elsewhere). +- Defines a \"Code\" environment (note the capital C), which all + \"Verbatim\" environments (provided by fvextra) will be wrapped with. + +A macro-like placeholder is used to set fvextra's defaults according to +`org-latex-engraved-options': + + [FVEXTRA-SETUP] + +In the default value the color \"EFD\" is provided as this is the +foreground colour provided by engrave-faces-latex. When there +are example/fixed-width blocks only, the engraved generated +preamble is not included, and so it is provided so we may use it +anyway." + :group 'org-export-latex + :type 'string + :package-version '(Org . "9.6")) + +(defcustom org-latex-engraved-options + '(("commandchars" . "\\\\\\{\\}") + ("highlightcolor" . "white!95!black!80!blue") + ("breaklines" . "true") + ("breaksymbol" . "\\color{white!60!black}\\tiny\\ensuremath{\\hookrightarrow}")) + "Association list of options for the latex fvextra package when engraving code. + +These options are set using \\fvset{...} in the preamble of the +LaTeX export. Each element of the alist should be a list or cons +cell containing two strings: the name of the option, and the +value. For example, + + (setq org-latex-engraved-options + \\='((\"highlightcolor\" \"green\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-engraved-options + \\='((\"highlightcolor\" . \"green\") (\"frame\" . \"lines\"))) + +will result in the following LaTeX in the preamble + +\\fvset{% + bgcolor=bg, + frame=lines} + +This will affect all fvextra environments. Note that the same +options will be applied to all blocks. If you need +block-specific options, you may use the following syntax: + + #+ATTR_LATEX: :options key1=value1,key2=value2 + #+BEGIN_SRC <LANG> + ... + #+END_SRC" + :group 'org-export-latex + :type '(alist :key-type (string :tag "option") + :value-type (string :tag "value"))) + +(defun org-latex-generate-engraved-preamble (info syntax-colours-p) + "Generate the preamble to setup engraved code. +The result is constructed from the :latex-engraved-preamble and +:latex-engraved-optionsn export options, the default values of +which are given by `org-latex-engraved-preamble' and +`org-latex-engraved-options' respectively." + (let* ((engraved-options + (plist-get info :latex-engraved-options)) + (engraved-preamble-template + (plist-get info :latex-engraved-preamble)) + (engraved-preamble + (if (string-match "^[ \t]*\\[FVEXTRA-SETUP\\][ \t]*\n?" + engraved-preamble-template) + (replace-match + (concat + "\\fvset{%\n " + (org-latex--make-option-string engraved-options ",\n ") + "}\n") + t t + engraved-preamble-template) + engraved-preamble-template))) + (if syntax-colours-p + (concat + "\n% Setup for code blocks [1/2]\n\n" + engraved-preamble + "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n" + (if (require 'engrave-faces-latex nil t) + (engrave-faces-latex-gen-preamble) + (message "Cannot engrave source blocks. Consider installing `engrave-faces'.") + "% WARNING syntax highlighting unavailible as engrave-faces-latex was missing.\n") + "\n") + (concat + "\n% Setup for code blocks\n\n" + engraved-preamble + "\n")))) ;;;; Compilation @@ -1756,6 +1908,17 @@ (defun org-latex-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template spec))) + ;; engrave-faces-latex preamble + (when (eq org-latex-listings 'engraved) + (let ((src-p (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity + info t)) + (fixedw-p + (org-element-map (plist-get info :parse-tree) + '(example-block fixed-width) #'identity + info t))) + (when (or src-p fixedw-p) + (org-latex-generate-engraved-preamble info src-p)))) ;; Document start. "\\begin{document}\n\n" ;; Title command. @@ -2142,6 +2305,7 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) (pcase (plist-get info :latex-listings) ('nil (org-latex--text-markup code 'code info)) ('minted (org-latex-inline-src-block--minted info code lang)) + ('engraved (org-latex-inline-src-block--engraved info code lang)) (_ (org-latex-inline-src-block--listings info code lang))))) (defun org-latex-inline-src-block--minted (info code lang) @@ -2157,6 +2321,11 @@ (defun org-latex-inline-src-block--minted (info code lang) mint-lang code))) +(defun org-latex-inline-src-block--engraved (_info code lang) + "Transcode an inline src block's content from Org to LaTeX, using engrave-faces. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (format "\\Verb{%s}" (org-latex-src--engrave-code code lang))) + (defun org-latex-inline-src-block--listings (info code lang) "Transcode an inline src block's content from Org to LaTeX, using lstlistings. INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." @@ -3017,6 +3186,9 @@ (defun org-latex-src-block (src-block _contents info) num-start retain-labels attributes float custom-env)) ((eq listings 'minted) (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) + ((eq listings 'engraved) + (org-latex-src-block--engraved src-block info lang caption caption-above-p label num-start retain-labels attributes float)) (t (org-latex-src-block--listings src-block info lang caption caption-above-p label @@ -3133,6 +3305,88 @@ (defun org-latex-src-block--minted ;; Return value. (format float-env body))) +(defun org-latex-src--engrave-code (content lang) + "Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result." + (if (require 'engrave-faces-latex nil t) + (let* ((lang-mode (and lang (org-src-get-lang-mode lang))) + (engraved-buffer + (with-temp-buffer + (insert content) + (when lang-mode + (if (functionp lang-mode) + (funcall lang-mode) + (message "Cannot engrave code as %s. %s is undefined." + lang lang-mode))) + (engrave-faces-latex-buffer))) + (engraved-code + (with-current-buffer engraved-buffer + (buffer-string)))) + (kill-buffer engraved-buffer) + engraved-code) + (user-error "Cannot engrave code as `engrave-faces-latex' is unavailible."))) + +(defun org-latex-src-block--engraved + (src-block info lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using engrave-faces-latex. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-engraved-options)) + (content + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'string-width + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))) + (body + (format + "\\begin{Code}\n\\begin{Verbatim}[%s]\n%s\\end{Verbatim}\n\\end{Code}" + ;; Options. + (concat + (org-latex--make-option-string + (append + (when (and num-start (not (assoc "linenos" options))) + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (list local-options)))))) + (org-latex-src--engrave-code content lang)))) + (format float-env body))) + (defun org-latex-src-block--listings (src-block info lang caption caption-above-p label num-start retain-labels attributes float) -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: 0005-ox-latex-Don-t-use-length-to-get-string-width.patch --] [-- Type: text/x-patch, Size: 1537 bytes --] From 96cf9853329dacd69745a225a889855dd13e5c2c Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sat, 7 May 2022 13:59:13 +0800 Subject: [PATCH 5/7] ox-latex: Don't use `length' to get string width * lisp/ox-latex.el (org-latex-src-block--listings, org-latex-src-block--engraved, org-latex-src-block--minted): Use `string-width' instead of `length' to gauge the displayed width of the string in LaTeX. This may not be a perfect match, but it should be an improvement. --- lisp/ox-latex.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 10cd6d76d..afd7ee48e 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -3286,7 +3286,7 @@ (defun org-latex-src-block--minted (let* ((code-info (org-export-unravel-code src-block)) (max-width (apply 'max - (mapcar 'length + (mapcar 'string-width (org-split-string (car code-info) "\n"))))) (org-export-format-code @@ -3438,7 +3438,7 @@ (defun org-latex-src-block--listings (let* ((code-info (org-export-unravel-code src-block)) (max-width (apply 'max - (mapcar 'length + (mapcar 'string-width (org-split-string (car code-info) "\n"))))) (org-export-format-code (car code-info) -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #7: 0006-ox-latex-Refactor-source-block-transcode-fun-sigs.patch --] [-- Type: text/x-patch, Size: 7297 bytes --] From f191a03ef97f5f8e29b18b73238ab659709ae230 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sat, 7 May 2022 14:02:44 +0800 Subject: [PATCH 6/7] ox-latex: Refactor source block transcode fun sigs * lisp/ox-latex.el (org-latex-src-block--listings, org-latex-src-block--engraved, org-latex-src-block--minted, org-latex-src-block--custom): Refactor these --backend functions to use cl-defun with keys instead of having an 11-argument signature. (org-latex-src-block): Adjust for the change in signature of the --backend functions, and refactor the `cond' statement to use `pcase'. --- lisp/ox-latex.el | 82 +++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index afd7ee48e..9150c1011 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -3166,37 +3166,37 @@ (defun org-latex-src-block (src-block _contents info) contextual information." (when (org-string-nw-p (org-element-property :value src-block)) (let* ((lang (org-element-property :language src-block)) - (caption (org-element-property :caption src-block)) - (caption-above-p (org-latex--caption-above-p src-block info)) - (label (org-element-property :name src-block)) - (custom-env (and lang - (cadr (assq (intern lang) - org-latex-custom-lang-environments)))) - (num-start (org-export-get-loc src-block info)) - (retain-labels (org-element-property :retain-labels src-block)) - (attributes (org-export-read-attribute :attr_latex src-block)) - (float (plist-get attributes :float)) - (listings (plist-get info :latex-listings))) - (cond - ((or (not lang) (not listings)) - (org-latex-src-block--verbatim src-block info lang caption caption-above-p label - num-start retain-labels attributes float)) - (custom-env - (org-latex-src-block--custom src-block info lang caption caption-above-p label - num-start retain-labels attributes float custom-env)) - ((eq listings 'minted) - (org-latex-src-block--minted src-block info lang caption caption-above-p label - num-start retain-labels attributes float)) - ((eq listings 'engraved) - (org-latex-src-block--engraved src-block info lang caption caption-above-p label - num-start retain-labels attributes float)) - (t - (org-latex-src-block--listings src-block info lang caption caption-above-p label - num-start retain-labels attributes float)))))) - -(defun org-latex-src-block--verbatim - (src-block info _lang caption caption-above-p _label - _num-start _retain-labels _attributes float) + (caption (org-element-property :caption src-block)) + (caption-above-p (org-latex--caption-above-p src-block info)) + (label (org-element-property :name src-block)) + (custom-env (and lang + (cadr (assq (intern lang) + org-latex-custom-lang-environments)))) + (num-start (org-export-get-loc src-block info)) + (retain-labels (org-element-property :retain-labels src-block)) + (attributes (org-export-read-attribute :attr_latex src-block)) + (float (plist-get attributes :float)) + (listings (plist-get info :latex-listings))) + (funcall + (pcase listings + ((or (pred not) (guard (not lang))) #'org-latex-src-block--verbatim) + ((guard custom-env) #'org-latex-src-block--custom) + ('minted #'org-latex-src-block--minted) + ('engraved #'org-latex-src-block--engraved) + (_ #'org-latex-src-block--listings)) + :src-block src-block + :info info + :lang lang + :caption caption + :caption-above-p caption-above-p + :label label + :num-start num-start + :retain-labels retain-labels + :attributes attributes + :float float)))) + +(cl-defun org-latex-src-block--verbatim + (&key src-block info caption caption-above-p float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using verbatim. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3215,9 +3215,8 @@ (defun org-latex-src-block--verbatim (if caption-above-p "" (concat "\n" caption-str)))) (t verbatim)))) -(defun org-latex-src-block--custom - (src-block info _lang caption caption-above-p _label - _num-start _retain-labels attributes float custom-env) +(cl-defun org-latex-src-block--custom + (&key src-block info caption caption-above-p attributes float custom-env &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using a custom environment. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3237,9 +3236,8 @@ (defun org-latex-src-block--custom (?l . ,(org-latex--label src-block info)) (?o . ,(or (plist-get attributes :options) ""))))))) -(defun org-latex-src-block--minted - (src-block info lang caption caption-above-p _label - num-start retain-labels attributes float) +(cl-defun org-latex-src-block--minted + (&key src-block info lang caption caption-above-p num-start retain-labels attributes float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using minted. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3325,9 +3323,8 @@ (defun org-latex-src--engrave-code (content lang) engraved-code) (user-error "Cannot engrave code as `engrave-faces-latex' is unavailible."))) -(defun org-latex-src-block--engraved - (src-block info lang caption caption-above-p _label - num-start retain-labels attributes float) +(cl-defun org-latex-src-block--engraved + (&key src-block info lang caption caption-above-p num-start retain-labels attributes float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using engrave-faces-latex. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3387,9 +3384,8 @@ (defun org-latex-src-block--engraved (org-latex-src--engrave-code content lang)))) (format float-env body))) -(defun org-latex-src-block--listings - (src-block info lang caption caption-above-p label - num-start retain-labels attributes float) +(cl-defun org-latex-src-block--listings + (&key src-block info lang caption caption-above-p label num-start retain-labels attributes float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using listings. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #8: 0007-ox-latex-Replace-org-latex-listings.patch --] [-- Type: text/x-patch, Size: 16128 bytes --] From adb4b6df3b4549fd6afd6cfb6ae8945e89882cfc Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sat, 7 May 2022 14:46:28 +0800 Subject: [PATCH 7/7] ox-latex: Replace `org-latex-listings' * lisp/ox-latex.el (org-latex-src-block, org-latex-keyword, org-latex-inline-src-block, org-latex-template, org-latex--caption/label-string, org-latex-engraved-preamble, org-latex-listings): Replace `org-latex-listings' with `org-latex-src-block-backend', which now can be set to listings/verbatim and no longer advertises t/nil as valid values. * lisp/ox-beamer.el (org-beamer-template): Update in the same manner as `org-latex-template'. * lisp/org-compat.el: Make `org-latex-listings' an obsolete alias for `org-latex-src-block-backend'. * testing/lisp/test-ox.el: Replace `org-latex-listings' reference with `org-latex-src-block-backend'. * doc/org-manual.org (Footnotes, LaTeX specific properties, Literal Examples): Replace references to `org-latex-listings' with `org-latex-src-block-backend'. * etc/ORG-NEWS: Add a news entry noting this change. The variable `org-latex-listings' originally indicated whether source blocks should use the listings LaTeX package, or not. This usage has evolved over the years, and now it sets one of four different fontification backends. This renaming should make the variable name a bit less misleading. --- doc/org-manual.org | 6 +-- etc/ORG-NEWS | 9 ++++ lisp/org-compat.el | 2 + lisp/ox-beamer.el | 2 +- lisp/ox-latex.el | 111 ++++++++++++++++++++++------------------ testing/lisp/test-ox.el | 2 +- 6 files changed, 78 insertions(+), 54 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index c0d38cd8c..60bded419 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -11159,7 +11159,7 @@ ** Literal Examples #+end_example #+cindex: formatting source code, markup rules -#+vindex: org-latex-listings +#+vindex: org-latex-src-block-backend If the example is source code from a programming language, or any other text that can be marked up by Font Lock in Emacs, you can ask for the example to look like the fontified Emacs buffer[fn:114]. This @@ -16304,12 +16304,12 @@ **** LaTeX specific properties | ~:latex-link-with-unknown-path-format~ | ~org-latex-link-with-unknown-path-format~ | | ~:latex-listings-langs~ | ~org-latex-listings-langs~ | | ~:latex-listings-options~ | ~org-latex-listings-options~ | -| ~:latex-listings~ | ~org-latex-listings~ | | ~:latex-minted-langs~ | ~org-latex-minted-langs~ | | ~:latex-minted-options~ | ~org-latex-minted-options~ | | ~:latex-prefer-user-labels~ | ~org-latex-prefer-user-labels~ | | ~:latex-subtitle-format~ | ~org-latex-subtitle-format~ | | ~:latex-subtitle-separate~ | ~org-latex-subtitle-separate~ | +| ~:latex-src-block-backend~ | ~org-latex-src-block-backend~ | | ~:latex-table-scientific-notation~ | ~org-latex-table-scientific-notation~ | | ~:latex-tables-booktabs~ | ~org-latex-tables-booktabs~ | | ~:latex-tables-centered~ | ~org-latex-tables-centered~ | @@ -22256,7 +22256,7 @@ * Footnotes version 1.34 of the =htmlize.el= package, which you need to install). Fontified code chunks in LaTeX can be achieved using either the [[https://www.ctan.org/pkg/listings][listings]] package or the [[https://www.ctan.org/pkg/minted][minted]] package. Refer to -~org-latex-listings~ for details. +~org-latex-src-block-backend~ for details. [fn:115] Source code in code blocks may also be evaluated either interactively or on export. See [[*Working with Source Code]] for more diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 1e8558c7b..c5f0bcb33 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -268,6 +268,15 @@ Chmod-style permissions are based on the new variable ~org-babel-tangle-default-file-mode~. *** A new custom setting =org-agenda-clock-report-header= to add a header to org agenda clock report + +*** ~org-latex-listings~ has been replaced with ~org-latex-src-block-backend~ + +~org-latex-listings~ has been renamed to better reflect the current +purpose of the variable. The replacement variable +~org-latex-src-block-backend~ acts in exactly the same way, however it +accepts =listings= and =verbatim= in place of =t= and =nil= (which +still work, but are no longer listed as valid options). + * Version 9.5 ** Important announcements and breaking changes diff --git a/lisp/org-compat.el b/lisp/org-compat.el index f599e246e..c1a78e834 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -324,6 +324,8 @@ (define-obsolete-variable-alias 'org-latex-create-formula-image-program 'org-preview-latex-default-process "9.0") (define-obsolete-variable-alias 'org-latex-preview-ltxpng-directory 'org-preview-latex-image-directory "9.0") +(define-obsolete-variable-alias 'org-latex-listings + 'org-latex-src-block-backend "9.6") (define-obsolete-function-alias 'org-table-p 'org-at-table-p "9.0") (define-obsolete-function-alias 'org-on-heading-p 'org-at-heading-p "9.0") (define-obsolete-function-alias 'org-at-regexp-p 'org-in-regexp "8.3") diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 4d40f6a1d..3baa4e26e 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -858,7 +858,7 @@ (defun org-beamer-template (contents info) (and (stringp template) (format-spec template (org-latex--format-spec info)))) ;; engrave-faces-latex preamble - (when (eq org-latex-listings 'engraved) + (when (eq org-latex-src-block-backend 'engraved) (let ((src-p (org-element-map (plist-get info :parse-tree) '(src-block inline-src-block) #'identity info t)) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 9150c1011..ffa89188b 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -143,7 +143,7 @@ (org-export-define-backend 'latex (:latex-inactive-timestamp-format nil nil org-latex-inactive-timestamp-format) (:latex-inline-image-rules nil nil org-latex-inline-image-rules) (:latex-link-with-unknown-path-format nil nil org-latex-link-with-unknown-path-format) - (:latex-listings nil nil org-latex-listings) + (:latex-src-block-backend nil nil org-latex-src-block-backend) (:latex-listings-langs nil nil org-latex-listings-langs) (:latex-listings-options nil nil org-latex-listings-options) (:latex-minted-langs nil nil org-latex-minted-langs) @@ -937,22 +937,22 @@ (defcustom org-latex-format-inlinetask-function ;; Src blocks -(defcustom org-latex-listings nil - "Non-nil means export source code using the listings package. +(defcustom org-latex-src-block-backend 'verbatim + "Backend used to generate source code listings. -This package will fontify source code, possibly even with color. -There are four implementations of this functionality you may +This sets the behaviour for fontifying source code, possibly even with +color. There are four implementations of this functionality you may choose from (ordered from least to most capable): -1. Verbatim (nil) -2. Listings (t) -3. Minted (minted) -4. Engraved (engraved) +1. Verbatim +2. Listings +3. Minted +4. Engraved The first two options provide basic syntax highlighting (listings), or none at all (verbatim). -When using listings, you also need to make use of the LaTeX -\"listings\" package. The \"color\" package is also needed if you +When using listings, you also need to make use of LaTeX package +\"listings\"e. The \"color\" LaTeX package is also needed if you would like color too. These can simply be added to `org-latex-packages-alist', using customise or something like: @@ -963,27 +963,12 @@ (defcustom org-latex-listings nil There are two further options for more comprehensive fontification. The first can be set with, - (setq org-latex-listings \\='engraved) + (setq org-latex-src-block-backend \\='minted) -which causes source code to be run through -`engrave-faces-latex-buffer', which generates colorings using -Emacs' font-lock information. This requires the engrave-faces -package (availible from ELPA), and the fvextra LaTeX package be -installed. - -The styling of the engraved result can customised with -`org-latex-engraved-preamble' and `org-latex-engraved-options'. -The default preamble also uses the tcolorbox LaTeX package in -addition to fvextra. - -The second more comprehensive option can be set with, - - (setq org-latex-listings \\='minted) - -which causes source code to be exported using the minted package -as opposed to listings. If you want to use minted, you need to -add the minted package to `org-latex-packages-alist', for example -using customize, or with +which causes source code to be exported using the LaTeX package +minted as opposed to listings. If you want to use minted, you +need to add the minted package to `org-latex-packages-alist', for +example using customize, or with (require \\='ox-latex) (add-to-list \\='org-latex-packages-alist \\='(\"newfloat\" \"minted\")) @@ -996,14 +981,29 @@ (defcustom org-latex-listings nil The minted choice has possible repercussions on the preview of latex fragments (see `org-preview-latex-fragment'). If you run into previewing problems, please consult -URL `https://orgmode.org/worg/org-tutorials/org-latex-preview.html'." +URL `https://orgmode.org/worg/org-tutorials/org-latex-preview.html'. + +The most comprehensive option can be set with, + + (setq org-latex-src-block-backend \\='engraved) + +which causes source code to be run through +`engrave-faces-latex-buffer', which generates colorings using +Emacs' font-lock information. This requires the Emacs package +engrave-faces (availible from ELPA), and the LaTeX package +fvextra be installed. + +The styling of the engraved result can customised with +`org-latex-engraved-preamble' and `org-latex-engraved-options'. +The default preamble also uses the LaTeX package tcolorbox in +addition to fvextra." :group 'org-export-latex :type '(choice - (const :tag "Use listings" t) + (const :tag "Use listings" listings) (const :tag "Use minted" minted) (const :tag "Use engrave-faces-latex" engraved) - (const :tag "Export verbatim" nil)) - :safe (lambda (s) (memq s '(t nil minted engraved)))) + (const :tag "Export verbatim" verbatim)) + :safe (lambda (s) (memq s '(listings minted engraved verbatim)))) (defcustom org-latex-listings-langs '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp") @@ -1201,7 +1201,7 @@ (defcustom org-latex-engraved-preamble right=2pt, top=1pt, bottom=0.5pt, breakable}" "Preamble content injected when using engrave-faces-latex for source blocks. -This is relevant when `org-latex-listings' is set to `engraved'. +This is relevant when `org-latex-src-block-backend' is set to `engraved'. There is quite a lot of flexibility in what this preamble can be, as long as it: - Loads the fvextra package. @@ -1502,7 +1502,8 @@ (defun org-latex--caption/label-string (element info) main) (and (eq type 'src-block) (not (plist-get attr :float)) - (null (plist-get info :latex-listings))))) + (memq (plist-get info :latex-src-block-backend) + '(verbatim nil))))) (short (org-export-get-caption element t)) (caption-from-attr-latex (plist-get attr :caption))) (cond @@ -1522,7 +1523,8 @@ (defun org-latex--caption/label-string (element info) (paragraph "figure") (image "figure") (special-block "figure") - (src-block (if (plist-get info :latex-listings) + (src-block (if (not (memq (plist-get info :latex-src-block-backend) + '(verbatim nil))) "listing" "figure")) (t (symbol-name type*))) @@ -1909,7 +1911,7 @@ (defun org-latex-template (contents info) (and (stringp template) (format-spec template spec))) ;; engrave-faces-latex preamble - (when (eq org-latex-listings 'engraved) + (when (eq org-latex-src-block-backend 'engraved) (let ((src-p (org-element-map (plist-get info :parse-tree) '(src-block inline-src-block) #'identity info t)) @@ -2302,11 +2304,17 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) contextual information." (let ((code (org-element-property :value inline-src-block)) (lang (org-element-property :language inline-src-block))) - (pcase (plist-get info :latex-listings) - ('nil (org-latex--text-markup code 'code info)) + (pcase (plist-get info :latex-src-block-backend) + ('verbatim (org-latex--text-markup code 'code info)) ('minted (org-latex-inline-src-block--minted info code lang)) ('engraved (org-latex-inline-src-block--engraved info code lang)) - (_ (org-latex-inline-src-block--listings info code lang))))) + ('listings (org-latex-inline-src-block--listings info code lang)) + (oldval + (message "Please update the LaTeX src-block-backend to %s" + (if oldval "listings" "verbatim")) + (if oldval + (org-latex-inline-src-block--listings info code lang) + (org-latex--text-markup code 'code info)))))) (defun org-latex-inline-src-block--minted (info code lang) "Transcode an inline src block's content from Org to LaTeX, using minted. @@ -2489,7 +2497,7 @@ (defun org-latex-keyword (keyword _contents info) (concat depth (and depth "\n") "\\tableofcontents")))) ((string-match-p "\\<tables\\>" value) "\\listoftables") ((string-match-p "\\<listings\\>" value) - (cl-case (plist-get info :latex-listings) + (cl-case (plist-get info :latex-src-block-backend) ((nil) "\\listoffigures") (minted "\\listoflistings") (otherwise "\\lstlistoflistings"))))))))) @@ -3175,15 +3183,20 @@ (defun org-latex-src-block (src-block _contents info) (num-start (org-export-get-loc src-block info)) (retain-labels (org-element-property :retain-labels src-block)) (attributes (org-export-read-attribute :attr_latex src-block)) - (float (plist-get attributes :float)) - (listings (plist-get info :latex-listings))) + (float (plist-get attributes :float))) (funcall - (pcase listings - ((or (pred not) (guard (not lang))) #'org-latex-src-block--verbatim) - ((guard custom-env) #'org-latex-src-block--custom) + (pcase (plist-get info :latex-src-block-backend) + ((or 'verbatim (guard (not lang))) #'org-latex-src-block--verbatim) ('minted #'org-latex-src-block--minted) ('engraved #'org-latex-src-block--engraved) - (_ #'org-latex-src-block--listings)) + ('listings #'org-latex-src-block--listings) + ((guard custom-env) #'org-latex-src-block--custom) + (oldval + (message "Please update the LaTeX src-block-backend to %s" + (if oldval "listings" "verbatim")) + (if oldval + #'org-latex-src-block--listings + #'org-latex-src-block--verbatim))) :src-block src-block :info info :lang lang diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el index 25e02b258..28f950813 100644 --- a/testing/lisp/test-ox.el +++ b/testing/lisp/test-ox.el @@ -3978,7 +3978,7 @@ (ert-deftest test-org-export/latex-src-block-verbatim-caption () \\end{verbatim} \\caption{Caption is below, 60\\%s} \\end{figure*}" - (let ((org-latex-listings 'minted) ; inactive due to missing lang + (let ((org-latex-src-block-backend 'minted) ; inactive due to missing lang (org-latex-default-figure-position "tp")) ;; Namely "multicolumn" value to get just figure environment ;; looks like a bug. -- 2.35.3 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-07 10:40 ` Timothy @ 2022-05-07 11:33 ` Daniel Fleischer 2022-05-08 14:30 ` [PATCH] (v2) " Timothy 0 siblings, 1 reply; 27+ messages in thread From: Daniel Fleischer @ 2022-05-07 11:33 UTC (permalink / raw) To: Timothy; +Cc: Ihor Radchenko, emacs-orgmode, Nicolas Goaziou Hi Timothy, Very nice set of patches, it looks good. Listings and minted are still workable options and your new engrave library is available. I must admit it's not clear how to customize faces since engrave is a bridge between major modes choices and latex but maybe show one or two examples (say elisp and python) of how to change/override some face. I think next we should apply these patches and be open to feedback about source code latex export using these new changes. I also wish there was a bit more documentation, but we can add more with time. Maybe some feedback from Nicolas G.? Best, -- Daniel Fleischer ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] (v2) New LaTeX code export option: engraved 2022-05-07 11:33 ` Daniel Fleischer @ 2022-05-08 14:30 ` Timothy 2022-05-09 6:20 ` Ihor Radchenko 2022-05-11 16:05 ` [PATCH] (v3) " Timothy 0 siblings, 2 replies; 27+ messages in thread From: Timothy @ 2022-05-08 14:30 UTC (permalink / raw) To: Daniel Fleischer; +Cc: Ihor Radchenko, emacs-orgmode, Nicolas Goaziou [-- Attachment #1: Type: text/plain, Size: 2337 bytes --] Hi Daniel & co., I have a new set of patches (attached), which make use of a major new feature in engrave-faces v0.3: engraved themes. Now, the theme used for source blocks can be set by the document keyword `#+latex_engraved_theme: THEME-NAME'. Furthermore, the theme can be customised on a per-code-block basis with `#+attr_latex: :engraved-theme THEME-NAME'. If you try this out, make sure you have the most recent commit of engrave-faces (531ea687e, soon to be released in v0.3.1). I’ve also fixed the “Bug: Percentage in caption (even escaped) does not work in LaTeX export” that Max raised (<https://list.orgmode.org/YT2PR01MB45101E27DC6251D8F8B7B366F6EC9@YT2PR01MB4510.CANPRD01.PROD.OUTLOOK.COM>). Daniel Fleischer <danflscr@gmail.com> writes: > Very nice set of patches, it looks good. Glad to hear you’ve been able to have a look over the patches. With the feedback I’ve received here so far, if no issues come up in the next few days I’m inclined to merge this, add documentation, and see what feedback pops up. > I must admit it’s not clear how to customize faces since engrave is a bridge > between major modes choices and latex but maybe show one or two examples (say > elisp and python) of how to change/override some face. Sure. The result should be visually identical to what you’d see in elisp/python buffer, but possibly with a different theme. Say you wanted to use a tweaked version of the default theme, this could be accomplished like so: ┌──── │ (setq default2 (alist-get 'default engrave-faces-themes)) │ ;; Make comments hot pink │ (plist-put (alist-get 'font-lock-comment-face default2) :foreground "#ff69b4") │ ;; Any other customisations... │ (add-to-list 'engrave-faces-themes (cons 'default2 default2)) └──── Then in the Org file you can use the “default2” engraved theme with `#+latex_engraved_theme: default2'. Let me know if there are any other examples you’d like to see. > I think next we should apply these patches and be open to feedback > about source code latex export using these new changes. I also wish > there was a bit more documentation, but we can add more with time. > Maybe some feedback from Nicolas G.? 👍 see my earlier comment on merging. All the best, Timothy [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-ox-latex-Refactor-org-latex-src-block.patch --] [-- Type: text/x-patch, Size: 15944 bytes --] From 18adbd0e1226cf3307090861e09e92bfa9cdfbf1 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 14:35:34 +0800 Subject: [PATCH 01/10] ox-latex: Refactor `org-latex-src-block' * lisp/ox-latex.el (org-latex-src-block): Extract the per-format logic from `org-latex-src-block' into new dedicated functions: + `org-latex-src-block--verbatim' + `org-latex-src-block--custom' + `org-latex-src-block--minted' + `org-latex-src-block--listings' This makes `org-latex-src-block' much less monolithic, taking it from 175 lines to 30, and I find also makes it easier to understand. --- lisp/ox-latex.el | 339 ++++++++++++++++++++++++++--------------------- 1 file changed, 185 insertions(+), 154 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 841ad48bc..c2f728a1c 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2997,164 +2997,195 @@ (defun org-latex-src-block (src-block _contents info) (float (plist-get attributes :float)) (listings (plist-get info :latex-listings))) (cond - ;; Case 1. No source fontification. ((or (not lang) (not listings)) - (let ((caption-str (org-latex--caption/label-string src-block info)) - (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" - (org-export-format-code-default src-block info)))) - (cond ((string= "multicolumn" float) - (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" - (plist-get info :latex-default-figure-position) - (if caption-above-p caption-str "") - verbatim - (if caption-above-p "" caption-str))) - (caption (concat - (if caption-above-p caption-str "") - verbatim - (if caption-above-p "" (concat "\n" caption-str)))) - (t verbatim)))) - ;; Case 2. Custom environment. + (org-latex-src-block--verbatim src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) (custom-env - (let ((caption-str (org-latex--caption/label-string src-block info)) - (formatted-src (org-export-format-code-default src-block info))) - (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) - (format "\\begin{%s}\n%s\\end{%s}\n" - custom-env - (concat (and caption-above-p caption-str) - formatted-src - (and (not caption-above-p) caption-str)) - custom-env) - (format-spec custom-env - `((?s . ,formatted-src) - (?c . ,caption) - (?f . ,float) - (?l . ,(org-latex--label src-block info)) - (?o . ,(or (plist-get attributes :options) ""))))))) - ;; Case 3. Use minted package. + (org-latex-src-block--custom src-block info lang caption caption-above-p label + num-start retain-labels attributes float custom-env)) ((eq listings 'minted) - (let* ((caption-str (org-latex--caption/label-string src-block info)) - (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) - (plist-get info :latex-default-figure-position))) - (float-env - (cond - ((string= "multicolumn" float) - (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - (caption - (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - ((string= "t" float) - (concat (format "\\begin{listing}[%s]\n" - placement) - "%s\n\\end{listing}")) - (t "%s"))) - (options (plist-get info :latex-minted-options)) - (body - (format - "\\begin{minted}[%s]{%s}\n%s\\end{minted}" - ;; Options. - (concat - (org-latex--make-option-string - (if (or (not num-start) (assoc "linenos" options)) - options - (append - `(("linenos") - ("firstnumber" ,(number-to-string (1+ num-start)))) - options))) - (let ((local-options (plist-get attributes :options))) - (and local-options (concat "," local-options)))) - ;; Language. - (or (cadr (assq (intern lang) - (plist-get info :latex-minted-langs))) - (downcase lang)) - ;; Source code. - (let* ((code-info (org-export-unravel-code src-block)) - (max-width - (apply 'max - (mapcar 'length - (org-split-string (car code-info) - "\n"))))) - (org-export-format-code - (car code-info) - (lambda (loc _num ref) - (concat - loc - (when ref - ;; Ensure references are flushed to the right, - ;; separated with 6 spaces from the widest line - ;; of code. - (concat (make-string (+ (- max-width (length loc)) 6) - ?\s) - (format "(%s)" ref))))) - nil (and retain-labels (cdr code-info))))))) - ;; Return value. - (format float-env body))) - ;; Case 4. Use listings package. + (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) (t - (let ((lst-lang - (or (cadr (assq (intern lang) - (plist-get info :latex-listings-langs))) - lang)) - (caption-str - (when caption - (let ((main (org-export-get-caption src-block)) - (secondary (org-export-get-caption src-block t))) - (if (not secondary) - (format "{%s}" (org-export-data main info)) - (format "{[%s]%s}" - (org-export-data secondary info) - (org-export-data main info)))))) - (lst-opt (plist-get info :latex-listings-options))) - (concat - ;; Options. - (format - "\\lstset{%s}\n" - (concat - (org-latex--make-option-string - (append - lst-opt - (cond - ((and (not float) (plist-member attributes :float)) nil) - ((string= "multicolumn" float) '(("float" "*"))) - ((and float (not (assoc "float" lst-opt))) - `(("float" ,(plist-get info :latex-default-figure-position))))) - `(("language" ,lst-lang)) - (if label - `(("label" ,(org-latex--label src-block info))) - '(("label" " "))) - (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) - `(("captionpos" ,(if caption-above-p "t" "b"))) - (cond ((assoc "numbers" lst-opt) nil) - ((not num-start) '(("numbers" "none"))) - (t `(("firstnumber" ,(number-to-string (1+ num-start))) - ("numbers" "left")))))) - (let ((local-options (plist-get attributes :options))) - (and local-options (concat "," local-options))))) - ;; Source code. - (format - "\\begin{lstlisting}\n%s\\end{lstlisting}" - (let* ((code-info (org-export-unravel-code src-block)) - (max-width - (apply 'max - (mapcar 'length - (org-split-string (car code-info) "\n"))))) - (org-export-format-code - (car code-info) - (lambda (loc _num ref) - (concat - loc - (when ref - ;; Ensure references are flushed to the right, - ;; separated with 6 spaces from the widest line of - ;; code - (concat (make-string (+ (- max-width (length loc)) 6) ?\s) - (format "(%s)" ref))))) - nil (and retain-labels (cdr code-info)))))))))))) - + (org-latex-src-block--listings src-block info lang caption caption-above-p label + num-start retain-labels attributes float)))))) + +(defun org-latex-src-block--verbatim + (src-block info _lang caption caption-above-p _label + _num-start _retain-labels _attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using verbatim. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((caption-str (org-latex--caption/label-string src-block info)) + (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" + (org-export-format-code-default src-block info)))) + (cond ((string= "multicolumn" float) + (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" + (plist-get info :latex-default-figure-position) + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" caption-str))) + (caption (concat + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" (concat "\n" caption-str)))) + (t verbatim)))) + +(defun org-latex-src-block--custom + (src-block info _lang caption caption-above-p _label + _num-start _retain-labels attributes float custom-env) + "Transcode a SRC-BLOCK element from Org to LaTeX, using a custom environment. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((caption-str (org-latex--caption/label-string src-block info)) + (formatted-src (org-export-format-code-default src-block info))) + (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) + (format "\\begin{%s}\n%s\\end{%s}\n" + custom-env + (concat (and caption-above-p caption-str) + formatted-src + (and (not caption-above-p) caption-str)) + custom-env) + (format-spec custom-env + `((?s . ,formatted-src) + (?c . ,caption) + (?f . ,float) + (?l . ,(org-latex--label src-block info)) + (?o . ,(or (plist-get attributes :options) ""))))))) + +(defun org-latex-src-block--minted + (src-block info lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using minted. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-minted-options)) + (body + (format + "\\begin{minted}[%s]{%s}\n%s\\end{minted}" + ;; Options. + (concat + (org-latex--make-option-string + (if (or (not num-start) (assoc "linenos" options)) + options + (append + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start)))) + options))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options)))) + ;; Language. + (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase lang)) + ;; Source code. + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))))) + ;; Return value. + (format float-env body))) + +(defun org-latex-src-block--listings + (src-block info lang caption caption-above-p label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using listings. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((lst-lang + (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + lang)) + (caption-str + (when caption + (let ((main (org-export-get-caption src-block)) + (secondary (org-export-get-caption src-block t))) + (if (not secondary) + (format "{%s}" (org-export-data main info)) + (format "{[%s]%s}" + (org-export-data secondary info) + (org-export-data main info)))))) + (lst-opt (plist-get info :latex-listings-options))) + (concat + ;; Options. + (format + "\\lstset{%s}\n" + (concat + (org-latex--make-option-string + (append + lst-opt + (cond + ((and (not float) (plist-member attributes :float)) nil) + ((string= "multicolumn" float) '(("float" "*"))) + ((and float (not (assoc "float" lst-opt))) + `(("float" ,(plist-get info :latex-default-figure-position))))) + `(("language" ,lst-lang)) + (if label + `(("label" ,(org-latex--label src-block info))) + '(("label" " "))) + (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) + `(("captionpos" ,(if caption-above-p "t" "b"))) + (cond ((assoc "numbers" lst-opt) nil) + ((not num-start) '(("numbers" "none"))) + (t `(("firstnumber" ,(number-to-string (1+ num-start))) + ("numbers" "left")))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options))))) + ;; Source code. + (format + "\\begin{lstlisting}\n%s\\end{lstlisting}" + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line of + ;; code + (concat (make-string (+ (- max-width (length loc)) 6) ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info)))))))) ;;;; Statistics Cookie -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-ox-latex-Refactor-org-latex-inline-src-block.patch --] [-- Type: text/x-patch, Size: 4018 bytes --] From 6635b72356192c3b0be500984b327d0b4ebd8e2b Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 4 May 2022 18:53:10 +0800 Subject: [PATCH 02/10] ox-latex: Refactor `org-latex-inline-src-block' * lisp/ox-latex.el (org-latex-inline-src-block, org-latex-inline-src-block--minted, org-latex-inline-src-block--listings): Extract the minted and listings specific logic out of `org-latex-inline-src-block` into the new functions `org-latex-inline-src-block--minted` and `org-latex-inline-src-block--listings`. --- lisp/ox-latex.el | 62 +++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index c2f728a1c..38f36a1f3 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2127,36 +2127,38 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) "Transcode an INLINE-SRC-BLOCK element from Org to LaTeX. CONTENTS holds the contents of the item. INFO is a plist holding contextual information." - (let* ((code (org-element-property :value inline-src-block)) - (separator (org-latex--find-verb-separator code))) - (cl-case (plist-get info :latex-listings) - ;; Do not use a special package: transcode it verbatim, as code. - ((nil) (org-latex--text-markup code 'code info)) - ;; Use minted package. - (minted - (let* ((org-lang (org-element-property :language inline-src-block)) - (mint-lang (or (cadr (assq (intern org-lang) - (plist-get info :latex-minted-langs))) - (downcase org-lang))) - (options (org-latex--make-option-string - (plist-get info :latex-minted-options)))) - (format "\\mintinline%s{%s}{%s}" - (if (string= options "") "" (format "[%s]" options)) - mint-lang - code))) - ;; Use listings package. - (otherwise - ;; Maybe translate language's name. - (let* ((org-lang (org-element-property :language inline-src-block)) - (lst-lang (or (cadr (assq (intern org-lang) - (plist-get info :latex-listings-langs))) - org-lang)) - (options (org-latex--make-option-string - (append (plist-get info :latex-listings-options) - `(("language" ,lst-lang)))))) - (concat (format "\\lstinline[%s]" options) - separator code separator)))))) - + (let ((code (org-element-property :value inline-src-block)) + (lang (org-element-property :language inline-src-block))) + (pcase (plist-get info :latex-listings) + ('nil (org-latex--text-markup code 'code info)) + ('minted (org-latex-inline-src-block--minted info code lang)) + (_ (org-latex-inline-src-block--listings info code lang))))) + +(defun org-latex-inline-src-block--minted (info code lang) + "Transcode an inline src block's content from Org to LaTeX, using minted. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (let ((mint-lang (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase lang))) + (options (org-latex--make-option-string + (plist-get info :latex-minted-options)))) + (format "\\mintinline%s{%s}{%s}" + (if (string= options "") "" (format "[%s]" options)) + mint-lang + code))) + +(defun org-latex-inline-src-block--listings (info code lang) + "Transcode an inline src block's content from Org to LaTeX, using lstlistings. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (let* ((lst-lang (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + lang)) + (separator (org-latex--find-verb-separator code)) + (options (org-latex--make-option-string + (append (plist-get info :latex-listings-options) + `(("language" ,lst-lang)))))) + (concat (format "\\lstinline[%s]" options) + separator code separator))) ;;;; Inlinetask -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-ox-latex-More-versitile-option-construction.patch --] [-- Type: text/x-patch, Size: 4118 bytes --] From 108f321a80de89c72974fc25fcde36c85023daca Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 4 May 2022 23:31:59 +0800 Subject: [PATCH 03/10] ox-latex: More versitile option construction * lisp/ox-latex.el (org-latex--make-option-string): Support a custom option seperator string. (org-latex--make-option-string, org-latex-minted-options, org-latex-listings-options): The first line of the docstrings for `org-latex-minted-options` and `org-latex-listings-options` describe the variables as "association lists", yet `org-latex--make-option-string` does not handle association lists and an example of two-value lists is provided. To make the behaviour match the docstring, `org-latex--make-option-string` is modified to work with either a list two-value lists or an association list, and the examples in `org-latex-minted-options` and `org-latex-listings-options` updated accordingly. --- lisp/ox-latex.el | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 38f36a1f3..2d4b3bace 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -1006,12 +1006,16 @@ (defcustom org-latex-listings-options nil These options are supplied as a comma-separated list to the \\lstset command. Each element of the association list should be -a list containing two strings: the name of the option, and the -value. For example, +a list or cons cell containing two strings: the name of the +option, and the value. For example, (setq org-latex-listings-options \\='((\"basicstyle\" \"\\\\small\") (\"keywordstyle\" \"\\\\color{black}\\\\bfseries\\\\underbar\"))) + ; or + (setq org-latex-listings-options + \\='((\"basicstyle\" . \"\\\\small\") + (\"keywordstyle\" . \"\\\\color{black}\\\\bfseries\\\\underbar\"))) will typeset the code in a small size font with underlined, bold black keywords. @@ -1059,11 +1063,14 @@ (defcustom org-latex-minted-options nil These options are supplied within square brackets in \\begin{minted} environments. Each element of the alist should -be a list containing two strings: the name of the option, and the -value. For example, +be a list or cons cell containing two strings: the name of the +option, and the value. For example, (setq org-latex-minted-options \\='((\"bgcolor\" \"bg\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-minted-options + \\='((\"bgcolor\" . \"bg\") (\"frame\" . \"lines\"))) will result in source blocks being exported with @@ -1506,21 +1513,24 @@ (defun org-latex--find-verb-separator (s) when (not (string-match (regexp-quote (char-to-string c)) s)) return (char-to-string c)))) -(defun org-latex--make-option-string (options) +(defun org-latex--make-option-string (options &optional seperator) "Return a comma separated string of keywords and values. OPTIONS is an alist where the key is the options keyword as a string, and the value a list containing the keyword value, or nil." (mapconcat (lambda (pair) - (pcase-let ((`(,keyword ,value) pair)) - (concat keyword - (and (> (length value) 0) - (concat "=" - (if (string-match-p (rx (any "[]")) value) - (format "{%s}" value) - value)))))) - options - ",")) + (let ((keyword (car pair)) + (value (pcase (cdr pair) + ((pred stringp) (cdr pair)) + ((pred consp) (cadr pair))))) + (concat keyword + (when value + (concat "=" + (if (string-match-p (rx (any "[]")) value) + (format "{%s}" value) + value)))))) + options + (or seperator ","))) (defun org-latex--wrap-label (element output info) "Wrap label associated to ELEMENT around OUTPUT, if appropriate. -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-ox-latex-Introduce-engraved-code-highlighting.patch --] [-- Type: text/x-patch, Size: 18190 bytes --] From 6f2edb89ff4dd5ce7d6618fc13fa83cbeb028e7b Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 20:04:12 +0800 Subject: [PATCH 04/10] ox-latex: Introduce "engraved" code highlighting * lisp/ox-latex.el (org-latex-src-block, org-latex-src-block--engraved, org-latex-inline-src-block, org-latex-inline-src-block--engraved, org-latex-src--engrave-code, org-latex-template, org-latex-listings): Make use of the engraved-faces package (available on ELPA) to provide an alternative LaTeX code highlighting backend which functions similarly to htmlize.el for HTML exports. (org-latex-engraved-preamble, org-latex-engraved-options): Introduce variables to construct the preamble for engraved code blocks. * lisp/ox-beamer.el (org-beamer-template): Modify to add engrave-faces preamble when applicable. --- lisp/ox-beamer.el | 11 ++ lisp/ox-latex.el | 294 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 296 insertions(+), 9 deletions(-) diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 6be73c91e..4d40f6a1d 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -857,6 +857,17 @@ (defun org-beamer-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template (org-latex--format-spec info)))) + ;; engrave-faces-latex preamble + (when (eq org-latex-listings 'engraved) + (let ((src-p (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity + info t)) + (fixedw-p + (org-element-map (plist-get info :parse-tree) + '(example-block fixed-width) #'identity + info t))) + (when (or src-p fixedw-p) + (org-latex-generate-engraved-preamble info src-p)))) ;; Document start. "\\begin{document}\n\n" ;; Title command. diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 2d4b3bace..1f4d4007d 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -37,6 +37,8 @@ (defvar org-latex-default-packages-alist) (defvar org-latex-packages-alist) (defvar orgtbl-exp-regexp) +(declare-function engrave-faces-latex-gen-preamble "ext:engrave-faces-latex") +(declare-function engrave-faces-latex-buffer "ext:engrave-faces-latex") \f ;;; Define Back-End @@ -125,6 +127,8 @@ (org-export-define-backend 'latex (:latex-default-quote-environment nil nil org-latex-default-quote-environment) (:latex-default-table-mode nil nil org-latex-default-table-mode) (:latex-diary-timestamp-format nil nil org-latex-diary-timestamp-format) + (:latex-engraved-options nil nil org-latex-engraved-options) + (:latex-engraved-preamble nil nil org-latex-engraved-preamble) (:latex-footnote-defined-format nil nil org-latex-footnote-defined-format) (:latex-footnote-separator nil nil org-latex-footnote-separator) (:latex-format-drawer-function nil nil org-latex-format-drawer-function) @@ -937,22 +941,48 @@ (defcustom org-latex-listings nil "Non-nil means export source code using the listings package. This package will fontify source code, possibly even with color. -If you want to use this, you also need to make LaTeX use the -listings package, and if you want to have color, the color -package. Just add these to `org-latex-packages-alist', for -example using customize, or with something like: +There are four implementations of this functionality you may +choose from (ordered from least to most capable): +1. Verbatim (nil) +2. Listings (t) +3. Minted (minted) +4. Engraved (engraved) + +The first two options provide basic syntax +highlighting (listings), or none at all (verbatim). + +When using listings, you also need to make use of the LaTeX +\"listings\" package. The \"color\" package is also needed if you +would like color too. These can simply be added to +`org-latex-packages-alist', using customise or something like: (require \\='ox-latex) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"listings\")) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"color\")) -Alternatively, +There are two further options for more comprehensive +fontification. The first can be set with, + + (setq org-latex-listings \\='engraved) + +which causes source code to be run through +`engrave-faces-latex-buffer', which generates colorings using +Emacs' font-lock information. This requires the engrave-faces +package (availible from ELPA), and the fvextra LaTeX package be +installed. + +The styling of the engraved result can customised with +`org-latex-engraved-preamble' and `org-latex-engraved-options'. +The default preamble also uses the tcolorbox LaTeX package in +addition to fvextra. + +The second more comprehensive option can be set with, (setq org-latex-listings \\='minted) -causes source code to be exported using the minted package as -opposed to listings. If you want to use minted, you need to add -the minted package to `org-latex-packages-alist', for example +which causes source code to be exported using the minted package +as opposed to listings. If you want to use minted, you need to +add the minted package to `org-latex-packages-alist', for example using customize, or with (require \\='ox-latex) @@ -971,8 +1001,9 @@ (defcustom org-latex-listings nil :type '(choice (const :tag "Use listings" t) (const :tag "Use minted" minted) + (const :tag "Use engrave-faces-latex" engraved) (const :tag "Export verbatim" nil)) - :safe (lambda (s) (memq s '(t nil minted)))) + :safe (lambda (s) (memq s '(t nil minted engraved)))) (defcustom org-latex-listings-langs '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp") @@ -1142,6 +1173,148 @@ (defcustom org-latex-custom-lang-environments nil :version "26.1" :package-version '(Org . "9.0")) +(defcustom org-latex-engraved-preamble + "\\usepackage{fvextra} + +[FVEXTRA-SETUP] + +% Make line numbers smaller and grey. +\\renewcommand\\theFancyVerbLine{\\footnotesize\\color{black!40!white}\\arabic{FancyVerbLine}} + +\\usepackage{xcolor} + +% In case engrave-faces-latex-gen-preamble has not been run. +\\providecolor{EfD}{HTML}{f7f7f7} +\\providecolor{EFD}{HTML}{28292e} + +% Define a Code environment to prettily wrap the fontified code. +\\usepackage[breakable,xparse]{tcolorbox} +\\DeclareTColorBox[]{Code}{o}% +{colback=EfD!98!EFD, colframe=EfD!95!EFD, + fontupper=\\footnotesize\\setlength{\\fboxsep}{0pt}, + colupper=EFD, + IfNoValueTF={#1}% + {boxsep=2pt, arc=2.5pt, outer arc=2.5pt, + boxrule=0.5pt, left=2pt}% + {boxsep=2.5pt, arc=0pt, outer arc=0pt, + boxrule=0pt, leftrule=1.5pt, left=0.5pt}, + right=2pt, top=1pt, bottom=0.5pt, + breakable} + +[LISTINGS-SETUP]" + "Preamble content injected when using engrave-faces-latex for source blocks. +This is relevant when `org-latex-listings' is set to `engraved'. + +There is quite a lot of flexibility in what this preamble can be, +as long as it: +- Loads the fvextra package. +- Loads the package xcolor (if it is not already loaded elsewhere). +- Defines a \"Code\" environment (note the capital C), which all + \"Verbatim\" environments (provided by fvextra) will be wrapped with. + +In the default value the color \"EFD\" is provided as this is the +foreground colour provided by engrave-faces-latex. When there +are example/fixed-width blocks only, the engraved generated +preamble is not included, and so it is provided so we may use it +anyway. + +Within this preamble there are two recognised macro-like placeholders: + + [FVEXTRA-SETUP] + + [LISTINGS-SETUP] + +FVEXTRA-SETUP sets fvextra's defaults according to +`org-latex-engraved-options', and LISTINGS-SETUP creates the +listings environment and defines \\listoflistings." + :group 'org-export-latex + :type 'string + :package-version '(Org . "9.6")) + +(defcustom org-latex-engraved-options + '(("commandchars" . "\\\\\\{\\}") + ("highlightcolor" . "white!95!black!80!blue") + ("breaklines" . "true") + ("breaksymbol" . "\\color{white!60!black}\\tiny\\ensuremath{\\hookrightarrow}")) + "Association list of options for the latex fvextra package when engraving code. + +These options are set using \\fvset{...} in the preamble of the +LaTeX export. Each element of the alist should be a list or cons +cell containing two strings: the name of the option, and the +value. For example, + + (setq org-latex-engraved-options + \\='((\"highlightcolor\" \"green\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-engraved-options + \\='((\"highlightcolor\" . \"green\") (\"frame\" . \"lines\"))) + +will result in the following LaTeX in the preamble + +\\fvset{% + bgcolor=bg, + frame=lines} + +This will affect all fvextra environments. Note that the same +options will be applied to all blocks. If you need +block-specific options, you may use the following syntax: + + #+ATTR_LATEX: :options key1=value1,key2=value2 + #+BEGIN_SRC <LANG> + ... + #+END_SRC" + :group 'org-export-latex + :type '(alist :key-type (string :tag "option") + :value-type (string :tag "value"))) + +(defun org-latex-generate-engraved-preamble (info syntax-colours-p) + "Generate the preamble to setup engraved code. +The result is constructed from the :latex-engraved-preamble and +:latex-engraved-optionsn export options, the default values of +which are given by `org-latex-engraved-preamble' and +`org-latex-engraved-options' respectively." + (let* ((engraved-options + (plist-get info :latex-engraved-options)) + (engraved-preamble (plist-get info :latex-engraved-preamble))) + (when (string-match "^[ \t]*\\[FVEXTRA-SETUP\\][ \t]*\n?" engraved-preamble) + (setq engraved-preamble + (replace-match + (concat + "\\fvset{%\n " + (org-latex--make-option-string engraved-options ",\n ") + "}\n") + t t + engraved-preamble))) + (when (string-match "^[ \t]*\\[LISTINGS-SETUP\\][ \t]*\n?" engraved-preamble) + (setq engraved-preamble + (replace-match + (format + "%% Support listings with captions +\\usepackage{float} +\\floatstyle{%s} +\\newfloat{listing}{htbp}{lst} +\\newcommand{\\listingsname}{Listing} +\\floatname{listing}{\\listingsname} +\\newcommand{\\listoflistingsname}{List of Listings} +\\providecommand{\\listoflistings}{\\listof{listing}{\\listoflistingsname}}\n" + (if (memq 'src-block org-latex-caption-above) + "plaintop" "plain")) + t t + engraved-preamble))) + (if syntax-colours-p + (concat + "\n% Setup for code blocks [1/2]\n\n" + engraved-preamble + "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n" + (if (require 'engrave-faces-latex nil t) + (engrave-faces-latex-gen-preamble) + (message "Cannot engrave source blocks. Consider installing `engrave-faces'.") + "% WARNING syntax highlighting unavailible as engrave-faces-latex was missing.\n") + "\n") + (concat + "\n% Setup for code blocks\n\n" + engraved-preamble + "\n")))) ;;;; Compilation @@ -1756,6 +1929,17 @@ (defun org-latex-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template spec))) + ;; engrave-faces-latex preamble + (when (eq org-latex-listings 'engraved) + (let ((src-p (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity + info t)) + (fixedw-p + (org-element-map (plist-get info :parse-tree) + '(example-block fixed-width) #'identity + info t))) + (when (or src-p fixedw-p) + (org-latex-generate-engraved-preamble info src-p)))) ;; Document start. "\\begin{document}\n\n" ;; Title command. @@ -2142,6 +2326,7 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) (pcase (plist-get info :latex-listings) ('nil (org-latex--text-markup code 'code info)) ('minted (org-latex-inline-src-block--minted info code lang)) + ('engraved (org-latex-inline-src-block--engraved info code lang)) (_ (org-latex-inline-src-block--listings info code lang))))) (defun org-latex-inline-src-block--minted (info code lang) @@ -2157,6 +2342,11 @@ (defun org-latex-inline-src-block--minted (info code lang) mint-lang code))) +(defun org-latex-inline-src-block--engraved (_info code lang) + "Transcode an inline src block's content from Org to LaTeX, using engrave-faces. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (format "\\Verb{%s}" (org-latex-src--engrave-code code lang))) + (defun org-latex-inline-src-block--listings (info code lang) "Transcode an inline src block's content from Org to LaTeX, using lstlistings. INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." @@ -2323,6 +2513,7 @@ (defun org-latex-keyword (keyword _contents info) (cl-case (plist-get info :latex-listings) ((nil) "\\listoffigures") (minted "\\listoflistings") + (engraved "\\listoflistings") (otherwise "\\lstlistoflistings"))))))))) @@ -3017,6 +3208,9 @@ (defun org-latex-src-block (src-block _contents info) num-start retain-labels attributes float custom-env)) ((eq listings 'minted) (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) + ((eq listings 'engraved) + (org-latex-src-block--engraved src-block info lang caption caption-above-p label num-start retain-labels attributes float)) (t (org-latex-src-block--listings src-block info lang caption caption-above-p label @@ -3133,6 +3327,88 @@ (defun org-latex-src-block--minted ;; Return value. (format float-env body))) +(defun org-latex-src--engrave-code (content lang) + "Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result." + (if (require 'engrave-faces-latex nil t) + (let* ((lang-mode (and lang (org-src-get-lang-mode lang))) + (engraved-buffer + (with-temp-buffer + (insert content) + (when lang-mode + (if (functionp lang-mode) + (funcall lang-mode) + (message "Cannot engrave code as %s. %s is undefined." + lang lang-mode))) + (engrave-faces-latex-buffer))) + (engraved-code + (with-current-buffer engraved-buffer + (buffer-string)))) + (kill-buffer engraved-buffer) + engraved-code) + (user-error "Cannot engrave code as `engrave-faces-latex' is unavailible."))) + +(defun org-latex-src-block--engraved + (src-block info lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using engrave-faces-latex. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-engraved-options)) + (content + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'string-width + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))) + (body + (format + "\\begin{Code}\n\\begin{Verbatim}[%s]\n%s\\end{Verbatim}\n\\end{Code}" + ;; Options. + (concat + (org-latex--make-option-string + (append + (when (and num-start (not (assoc "linenos" options))) + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (list local-options)))))) + (org-latex-src--engrave-code content lang)))) + (format float-env body))) + (defun org-latex-src-block--listings (src-block info lang caption caption-above-p label num-start retain-labels attributes float) -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: 0005-ox-latex-Don-t-use-length-to-get-string-width.patch --] [-- Type: text/x-patch, Size: 1539 bytes --] From 27a83b36b77e267feb3267d6a4dffd16fdf1d5a7 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sat, 7 May 2022 13:59:13 +0800 Subject: [PATCH 05/10] ox-latex: Don't use `length' to get string width * lisp/ox-latex.el (org-latex-src-block--listings, org-latex-src-block--engraved, org-latex-src-block--minted): Use `string-width' instead of `length' to gauge the displayed width of the string in LaTeX. This may not be a perfect match, but it should be an improvement. --- lisp/ox-latex.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 1f4d4007d..13ba6cd8c 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -3308,7 +3308,7 @@ (defun org-latex-src-block--minted (let* ((code-info (org-export-unravel-code src-block)) (max-width (apply 'max - (mapcar 'length + (mapcar 'string-width (org-split-string (car code-info) "\n"))))) (org-export-format-code @@ -3460,7 +3460,7 @@ (defun org-latex-src-block--listings (let* ((code-info (org-export-unravel-code src-block)) (max-width (apply 'max - (mapcar 'length + (mapcar 'string-width (org-split-string (car code-info) "\n"))))) (org-export-format-code (car code-info) -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #7: 0006-ox-latex-Refactor-source-block-transcode-fun-sigs.patch --] [-- Type: text/x-patch, Size: 7299 bytes --] From ce7b8d8d1eafa6f2e6d0e247661000fc5272a24c Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sat, 7 May 2022 14:02:44 +0800 Subject: [PATCH 06/10] ox-latex: Refactor source block transcode fun sigs * lisp/ox-latex.el (org-latex-src-block--listings, org-latex-src-block--engraved, org-latex-src-block--minted, org-latex-src-block--custom): Refactor these --backend functions to use cl-defun with keys instead of having an 11-argument signature. (org-latex-src-block): Adjust for the change in signature of the --backend functions, and refactor the `cond' statement to use `pcase'. --- lisp/ox-latex.el | 82 +++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 13ba6cd8c..4421bb8f5 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -3188,37 +3188,37 @@ (defun org-latex-src-block (src-block _contents info) contextual information." (when (org-string-nw-p (org-element-property :value src-block)) (let* ((lang (org-element-property :language src-block)) - (caption (org-element-property :caption src-block)) - (caption-above-p (org-latex--caption-above-p src-block info)) - (label (org-element-property :name src-block)) - (custom-env (and lang - (cadr (assq (intern lang) - org-latex-custom-lang-environments)))) - (num-start (org-export-get-loc src-block info)) - (retain-labels (org-element-property :retain-labels src-block)) - (attributes (org-export-read-attribute :attr_latex src-block)) - (float (plist-get attributes :float)) - (listings (plist-get info :latex-listings))) - (cond - ((or (not lang) (not listings)) - (org-latex-src-block--verbatim src-block info lang caption caption-above-p label - num-start retain-labels attributes float)) - (custom-env - (org-latex-src-block--custom src-block info lang caption caption-above-p label - num-start retain-labels attributes float custom-env)) - ((eq listings 'minted) - (org-latex-src-block--minted src-block info lang caption caption-above-p label - num-start retain-labels attributes float)) - ((eq listings 'engraved) - (org-latex-src-block--engraved src-block info lang caption caption-above-p label - num-start retain-labels attributes float)) - (t - (org-latex-src-block--listings src-block info lang caption caption-above-p label - num-start retain-labels attributes float)))))) - -(defun org-latex-src-block--verbatim - (src-block info _lang caption caption-above-p _label - _num-start _retain-labels _attributes float) + (caption (org-element-property :caption src-block)) + (caption-above-p (org-latex--caption-above-p src-block info)) + (label (org-element-property :name src-block)) + (custom-env (and lang + (cadr (assq (intern lang) + org-latex-custom-lang-environments)))) + (num-start (org-export-get-loc src-block info)) + (retain-labels (org-element-property :retain-labels src-block)) + (attributes (org-export-read-attribute :attr_latex src-block)) + (float (plist-get attributes :float)) + (listings (plist-get info :latex-listings))) + (funcall + (pcase listings + ((or (pred not) (guard (not lang))) #'org-latex-src-block--verbatim) + ((guard custom-env) #'org-latex-src-block--custom) + ('minted #'org-latex-src-block--minted) + ('engraved #'org-latex-src-block--engraved) + (_ #'org-latex-src-block--listings)) + :src-block src-block + :info info + :lang lang + :caption caption + :caption-above-p caption-above-p + :label label + :num-start num-start + :retain-labels retain-labels + :attributes attributes + :float float)))) + +(cl-defun org-latex-src-block--verbatim + (&key src-block info caption caption-above-p float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using verbatim. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3237,9 +3237,8 @@ (defun org-latex-src-block--verbatim (if caption-above-p "" (concat "\n" caption-str)))) (t verbatim)))) -(defun org-latex-src-block--custom - (src-block info _lang caption caption-above-p _label - _num-start _retain-labels attributes float custom-env) +(cl-defun org-latex-src-block--custom + (&key src-block info caption caption-above-p attributes float custom-env &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using a custom environment. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3259,9 +3258,8 @@ (defun org-latex-src-block--custom (?l . ,(org-latex--label src-block info)) (?o . ,(or (plist-get attributes :options) ""))))))) -(defun org-latex-src-block--minted - (src-block info lang caption caption-above-p _label - num-start retain-labels attributes float) +(cl-defun org-latex-src-block--minted + (&key src-block info lang caption caption-above-p num-start retain-labels attributes float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using minted. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3347,9 +3345,8 @@ (defun org-latex-src--engrave-code (content lang) engraved-code) (user-error "Cannot engrave code as `engrave-faces-latex' is unavailible."))) -(defun org-latex-src-block--engraved - (src-block info lang caption caption-above-p _label - num-start retain-labels attributes float) +(cl-defun org-latex-src-block--engraved + (&key src-block info lang caption caption-above-p num-start retain-labels attributes float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using engrave-faces-latex. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3409,9 +3406,8 @@ (defun org-latex-src-block--engraved (org-latex-src--engrave-code content lang)))) (format float-env body))) -(defun org-latex-src-block--listings - (src-block info lang caption caption-above-p label - num-start retain-labels attributes float) +(cl-defun org-latex-src-block--listings + (&key src-block info lang caption caption-above-p label num-start retain-labels attributes float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using listings. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #8: 0007-ox-latex-Replace-org-latex-listings.patch --] [-- Type: text/x-patch, Size: 16058 bytes --] From 17e91e6816eeeed398a7f2779108e499729005c8 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sat, 7 May 2022 14:46:28 +0800 Subject: [PATCH 07/10] ox-latex: Replace `org-latex-listings' * lisp/ox-latex.el (org-latex-src-block, org-latex-keyword, org-latex-inline-src-block, org-latex-template, org-latex--caption/label-string, org-latex-engraved-preamble, org-latex-listings): Replace `org-latex-listings' with `org-latex-src-block-backend', which now can be set to listings/verbatim and no longer advertises t/nil as valid values. * lisp/ox-beamer.el (org-beamer-template): Update in the same manner as `org-latex-template'. * lisp/org-compat.el: Make `org-latex-listings' an obsolete alias for `org-latex-src-block-backend'. * testing/lisp/test-ox.el: Replace `org-latex-listings' reference with `org-latex-src-block-backend'. * doc/org-manual.org (Footnotes, LaTeX specific properties, Literal Examples): Replace references to `org-latex-listings' with `org-latex-src-block-backend'. * etc/ORG-NEWS: Add a news entry noting this change. The variable `org-latex-listings' originally indicated whether source blocks should use the listings LaTeX package, or not. This usage has evolved over the years, and now it sets one of four different fontification backends. This renaming should make the variable name a bit less misleading. --- doc/org-manual.org | 6 +-- etc/ORG-NEWS | 9 ++++ lisp/org-compat.el | 2 + lisp/ox-beamer.el | 2 +- lisp/ox-latex.el | 111 ++++++++++++++++++++++------------------ testing/lisp/test-ox.el | 2 +- 6 files changed, 78 insertions(+), 54 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index c0d38cd8c..60bded419 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -11159,7 +11159,7 @@ ** Literal Examples #+end_example #+cindex: formatting source code, markup rules -#+vindex: org-latex-listings +#+vindex: org-latex-src-block-backend If the example is source code from a programming language, or any other text that can be marked up by Font Lock in Emacs, you can ask for the example to look like the fontified Emacs buffer[fn:114]. This @@ -16304,12 +16304,12 @@ **** LaTeX specific properties | ~:latex-link-with-unknown-path-format~ | ~org-latex-link-with-unknown-path-format~ | | ~:latex-listings-langs~ | ~org-latex-listings-langs~ | | ~:latex-listings-options~ | ~org-latex-listings-options~ | -| ~:latex-listings~ | ~org-latex-listings~ | | ~:latex-minted-langs~ | ~org-latex-minted-langs~ | | ~:latex-minted-options~ | ~org-latex-minted-options~ | | ~:latex-prefer-user-labels~ | ~org-latex-prefer-user-labels~ | | ~:latex-subtitle-format~ | ~org-latex-subtitle-format~ | | ~:latex-subtitle-separate~ | ~org-latex-subtitle-separate~ | +| ~:latex-src-block-backend~ | ~org-latex-src-block-backend~ | | ~:latex-table-scientific-notation~ | ~org-latex-table-scientific-notation~ | | ~:latex-tables-booktabs~ | ~org-latex-tables-booktabs~ | | ~:latex-tables-centered~ | ~org-latex-tables-centered~ | @@ -22256,7 +22256,7 @@ * Footnotes version 1.34 of the =htmlize.el= package, which you need to install). Fontified code chunks in LaTeX can be achieved using either the [[https://www.ctan.org/pkg/listings][listings]] package or the [[https://www.ctan.org/pkg/minted][minted]] package. Refer to -~org-latex-listings~ for details. +~org-latex-src-block-backend~ for details. [fn:115] Source code in code blocks may also be evaluated either interactively or on export. See [[*Working with Source Code]] for more diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 27de6da62..ebb3cd649 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -273,6 +273,15 @@ Chmod-style permissions are based on the new variable ~org-babel-tangle-default-file-mode~. *** A new custom setting =org-agenda-clock-report-header= to add a header to org agenda clock report + +*** ~org-latex-listings~ has been replaced with ~org-latex-src-block-backend~ + +~org-latex-listings~ has been renamed to better reflect the current +purpose of the variable. The replacement variable +~org-latex-src-block-backend~ acts in exactly the same way, however it +accepts =listings= and =verbatim= in place of =t= and =nil= (which +still work, but are no longer listed as valid options). + * Version 9.5 ** Important announcements and breaking changes diff --git a/lisp/org-compat.el b/lisp/org-compat.el index a29f206a4..704197645 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -324,6 +324,8 @@ (define-obsolete-variable-alias 'org-latex-create-formula-image-program 'org-preview-latex-default-process "9.0") (define-obsolete-variable-alias 'org-latex-preview-ltxpng-directory 'org-preview-latex-image-directory "9.0") +(define-obsolete-variable-alias 'org-latex-listings + 'org-latex-src-block-backend "9.6") (define-obsolete-function-alias 'org-table-p 'org-at-table-p "9.0") (define-obsolete-function-alias 'org-on-heading-p 'org-at-heading-p "9.0") (define-obsolete-function-alias 'org-at-regexp-p 'org-in-regexp "8.3") diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 4d40f6a1d..3baa4e26e 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -858,7 +858,7 @@ (defun org-beamer-template (contents info) (and (stringp template) (format-spec template (org-latex--format-spec info)))) ;; engrave-faces-latex preamble - (when (eq org-latex-listings 'engraved) + (when (eq org-latex-src-block-backend 'engraved) (let ((src-p (org-element-map (plist-get info :parse-tree) '(src-block inline-src-block) #'identity info t)) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 4421bb8f5..cc6ac291a 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -143,7 +143,7 @@ (org-export-define-backend 'latex (:latex-inactive-timestamp-format nil nil org-latex-inactive-timestamp-format) (:latex-inline-image-rules nil nil org-latex-inline-image-rules) (:latex-link-with-unknown-path-format nil nil org-latex-link-with-unknown-path-format) - (:latex-listings nil nil org-latex-listings) + (:latex-src-block-backend nil nil org-latex-src-block-backend) (:latex-listings-langs nil nil org-latex-listings-langs) (:latex-listings-options nil nil org-latex-listings-options) (:latex-minted-langs nil nil org-latex-minted-langs) @@ -937,22 +937,22 @@ (defcustom org-latex-format-inlinetask-function ;; Src blocks -(defcustom org-latex-listings nil - "Non-nil means export source code using the listings package. +(defcustom org-latex-src-block-backend 'verbatim + "Backend used to generate source code listings. -This package will fontify source code, possibly even with color. -There are four implementations of this functionality you may +This sets the behaviour for fontifying source code, possibly even with +color. There are four implementations of this functionality you may choose from (ordered from least to most capable): -1. Verbatim (nil) -2. Listings (t) -3. Minted (minted) -4. Engraved (engraved) +1. Verbatim +2. Listings +3. Minted +4. Engraved The first two options provide basic syntax highlighting (listings), or none at all (verbatim). -When using listings, you also need to make use of the LaTeX -\"listings\" package. The \"color\" package is also needed if you +When using listings, you also need to make use of LaTeX package +\"listings\"e. The \"color\" LaTeX package is also needed if you would like color too. These can simply be added to `org-latex-packages-alist', using customise or something like: @@ -963,27 +963,12 @@ (defcustom org-latex-listings nil There are two further options for more comprehensive fontification. The first can be set with, - (setq org-latex-listings \\='engraved) + (setq org-latex-src-block-backend \\='minted) -which causes source code to be run through -`engrave-faces-latex-buffer', which generates colorings using -Emacs' font-lock information. This requires the engrave-faces -package (availible from ELPA), and the fvextra LaTeX package be -installed. - -The styling of the engraved result can customised with -`org-latex-engraved-preamble' and `org-latex-engraved-options'. -The default preamble also uses the tcolorbox LaTeX package in -addition to fvextra. - -The second more comprehensive option can be set with, - - (setq org-latex-listings \\='minted) - -which causes source code to be exported using the minted package -as opposed to listings. If you want to use minted, you need to -add the minted package to `org-latex-packages-alist', for example -using customize, or with +which causes source code to be exported using the LaTeX package +minted as opposed to listings. If you want to use minted, you +need to add the minted package to `org-latex-packages-alist', for +example using customize, or with (require \\='ox-latex) (add-to-list \\='org-latex-packages-alist \\='(\"newfloat\" \"minted\")) @@ -996,14 +981,29 @@ (defcustom org-latex-listings nil The minted choice has possible repercussions on the preview of latex fragments (see `org-preview-latex-fragment'). If you run into previewing problems, please consult -URL `https://orgmode.org/worg/org-tutorials/org-latex-preview.html'." +URL `https://orgmode.org/worg/org-tutorials/org-latex-preview.html'. + +The most comprehensive option can be set with, + + (setq org-latex-src-block-backend \\='engraved) + +which causes source code to be run through +`engrave-faces-latex-buffer', which generates colorings using +Emacs' font-lock information. This requires the Emacs package +engrave-faces (availible from ELPA), and the LaTeX package +fvextra be installed. + +The styling of the engraved result can customised with +`org-latex-engraved-preamble' and `org-latex-engraved-options'. +The default preamble also uses the LaTeX package tcolorbox in +addition to fvextra." :group 'org-export-latex :type '(choice - (const :tag "Use listings" t) + (const :tag "Use listings" listings) (const :tag "Use minted" minted) (const :tag "Use engrave-faces-latex" engraved) - (const :tag "Export verbatim" nil)) - :safe (lambda (s) (memq s '(t nil minted engraved)))) + (const :tag "Export verbatim" verbatim)) + :safe (lambda (s) (memq s '(listings minted engraved verbatim)))) (defcustom org-latex-listings-langs '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp") @@ -1203,7 +1203,7 @@ (defcustom org-latex-engraved-preamble [LISTINGS-SETUP]" "Preamble content injected when using engrave-faces-latex for source blocks. -This is relevant when `org-latex-listings' is set to `engraved'. +This is relevant when `org-latex-src-block-backend' is set to `engraved'. There is quite a lot of flexibility in what this preamble can be, as long as it: @@ -1523,7 +1523,8 @@ (defun org-latex--caption/label-string (element info) main) (and (eq type 'src-block) (not (plist-get attr :float)) - (null (plist-get info :latex-listings))))) + (memq (plist-get info :latex-src-block-backend) + '(verbatim nil))))) (short (org-export-get-caption element t)) (caption-from-attr-latex (plist-get attr :caption))) (cond @@ -1543,7 +1544,8 @@ (defun org-latex--caption/label-string (element info) (paragraph "figure") (image "figure") (special-block "figure") - (src-block (if (plist-get info :latex-listings) + (src-block (if (not (memq (plist-get info :latex-src-block-backend) + '(verbatim nil))) "listing" "figure")) (t (symbol-name type*))) @@ -1930,7 +1932,7 @@ (defun org-latex-template (contents info) (and (stringp template) (format-spec template spec))) ;; engrave-faces-latex preamble - (when (eq org-latex-listings 'engraved) + (when (eq org-latex-src-block-backend 'engraved) (let ((src-p (org-element-map (plist-get info :parse-tree) '(src-block inline-src-block) #'identity info t)) @@ -2323,11 +2325,17 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) contextual information." (let ((code (org-element-property :value inline-src-block)) (lang (org-element-property :language inline-src-block))) - (pcase (plist-get info :latex-listings) - ('nil (org-latex--text-markup code 'code info)) + (pcase (plist-get info :latex-src-block-backend) + ('verbatim (org-latex--text-markup code 'code info)) ('minted (org-latex-inline-src-block--minted info code lang)) ('engraved (org-latex-inline-src-block--engraved info code lang)) - (_ (org-latex-inline-src-block--listings info code lang))))) + ('listings (org-latex-inline-src-block--listings info code lang)) + (oldval + (message "Please update the LaTeX src-block-backend to %s" + (if oldval "listings" "verbatim")) + (if oldval + (org-latex-inline-src-block--listings info code lang) + (org-latex--text-markup code 'code info)))))) (defun org-latex-inline-src-block--minted (info code lang) "Transcode an inline src block's content from Org to LaTeX, using minted. @@ -2510,7 +2518,7 @@ (defun org-latex-keyword (keyword _contents info) (concat depth (and depth "\n") "\\tableofcontents")))) ((string-match-p "\\<tables\\>" value) "\\listoftables") ((string-match-p "\\<listings\\>" value) - (cl-case (plist-get info :latex-listings) + (cl-case (plist-get info :latex-src-block-backend) ((nil) "\\listoffigures") (minted "\\listoflistings") (engraved "\\listoflistings") @@ -3197,15 +3205,20 @@ (defun org-latex-src-block (src-block _contents info) (num-start (org-export-get-loc src-block info)) (retain-labels (org-element-property :retain-labels src-block)) (attributes (org-export-read-attribute :attr_latex src-block)) - (float (plist-get attributes :float)) - (listings (plist-get info :latex-listings))) + (float (plist-get attributes :float))) (funcall - (pcase listings - ((or (pred not) (guard (not lang))) #'org-latex-src-block--verbatim) - ((guard custom-env) #'org-latex-src-block--custom) + (pcase (plist-get info :latex-src-block-backend) + ((or 'verbatim (guard (not lang))) #'org-latex-src-block--verbatim) ('minted #'org-latex-src-block--minted) ('engraved #'org-latex-src-block--engraved) - (_ #'org-latex-src-block--listings)) + ('listings #'org-latex-src-block--listings) + ((guard custom-env) #'org-latex-src-block--custom) + (oldval + (message "Please update the LaTeX src-block-backend to %s" + (if oldval "listings" "verbatim")) + (if oldval + #'org-latex-src-block--listings + #'org-latex-src-block--verbatim))) :src-block src-block :info info :lang lang diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el index 25e02b258..28f950813 100644 --- a/testing/lisp/test-ox.el +++ b/testing/lisp/test-ox.el @@ -3978,7 +3978,7 @@ (ert-deftest test-org-export/latex-src-block-verbatim-caption () \\end{verbatim} \\caption{Caption is below, 60\\%s} \\end{figure*}" - (let ((org-latex-listings 'minted) ; inactive due to missing lang + (let ((org-latex-src-block-backend 'minted) ; inactive due to missing lang (org-latex-default-figure-position "tp")) ;; Namely "multicolumn" value to get just figure environment ;; looks like a bug. -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #9: 0008-ox-latex-Support-setting-the-engraved-theme.patch --] [-- Type: text/x-patch, Size: 3181 bytes --] From 146146df02434f8b224b21293753f260d0d624b2 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 8 May 2022 02:01:34 +0800 Subject: [PATCH 08/10] ox-latex: Support setting the engraved theme * lisp/ox-latex.el (org-latex-generate-engraved-preamble, org-latex-engraved-theme): Introduce the new export keyword LATEX_ENGRAVED_THEME with default value given by `org-latex-engraved-theme'. This is used to set the engraved theme used in org-latex-engraved-theme. This bumps the minimum required version of engrave-faces from v0.2 to v0.3. --- lisp/ox-latex.el | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index cc6ac291a..21541e9aa 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -129,6 +129,7 @@ (org-export-define-backend 'latex (:latex-diary-timestamp-format nil nil org-latex-diary-timestamp-format) (:latex-engraved-options nil nil org-latex-engraved-options) (:latex-engraved-preamble nil nil org-latex-engraved-preamble) + (:latex-engraved-theme "LATEX_ENGRAVED_THEME" nil org-latex-engraved-theme) (:latex-footnote-defined-format nil nil org-latex-footnote-defined-format) (:latex-footnote-separator nil nil org-latex-footnote-separator) (:latex-format-drawer-function nil nil org-latex-format-drawer-function) @@ -1267,6 +1268,14 @@ (defcustom org-latex-engraved-options :type '(alist :key-type (string :tag "option") :value-type (string :tag "value"))) +(defcustom org-latex-engraved-theme nil + "The theme that should be used for engraved code, when non-nil. +This can be set to any theme defined in `engrave-faces-themes' or +loadable by Emacs. When set to t, the current Emacs theme is +used." + :group 'org-export-latex + :type 'symbol) + (defun org-latex-generate-engraved-preamble (info syntax-colours-p) "Generate the preamble to setup engraved code. The result is constructed from the :latex-engraved-preamble and @@ -1275,7 +1284,8 @@ (defun org-latex-generate-engraved-preamble (info syntax-colours-p) `org-latex-engraved-options' respectively." (let* ((engraved-options (plist-get info :latex-engraved-options)) - (engraved-preamble (plist-get info :latex-engraved-preamble))) + (engraved-preamble (plist-get info :latex-engraved-preamble)) + (engraved-theme (plist-get info :latex-engraved-theme))) (when (string-match "^[ \t]*\\[FVEXTRA-SETUP\\][ \t]*\n?" engraved-preamble) (setq engraved-preamble (replace-match @@ -1307,7 +1317,8 @@ (defun org-latex-generate-engraved-preamble (info syntax-colours-p) engraved-preamble "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n" (if (require 'engrave-faces-latex nil t) - (engrave-faces-latex-gen-preamble) + (engrave-faces-latex-gen-preamble + (when engraved-theme (intern engraved-theme))) (message "Cannot engrave source blocks. Consider installing `engrave-faces'.") "% WARNING syntax highlighting unavailible as engrave-faces-latex was missing.\n") "\n") -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #10: 0009-ox-latex-Support-setting-engraved-theme-per-block.patch --] [-- Type: text/x-patch, Size: 8907 bytes --] From dc4989ccf41f09e7fce08036f89e9274ead4e257 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 8 May 2022 15:28:29 +0800 Subject: [PATCH 09/10] ox-latex: Support setting engraved theme per-block * lisp/ox-latex.el (org-latex-src-block--engraved, org-latex-src--engrave-code, org-latex-inline-src-block--engraved, org-latex-generate-engraved-preamble): Allow for the engraved theme used to be set on a per-src-block basis with #+attr_latex: :engraved-theme THEME. Extra setup code is now generated in `org-latex-generate-engraved-preamble'. To facilitate the application of themes to src blocks, `org-latex-src--engrave-code' now takes on a larger portion of the transcoding work. --- lisp/ox-latex.el | 113 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 89 insertions(+), 24 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 21541e9aa..528243a59 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -1285,7 +1285,27 @@ (defun org-latex-generate-engraved-preamble (info syntax-colours-p) (let* ((engraved-options (plist-get info :latex-engraved-options)) (engraved-preamble (plist-get info :latex-engraved-preamble)) - (engraved-theme (plist-get info :latex-engraved-theme))) + (engraved-theme (plist-get info :latex-engraved-theme)) + (engraved-themes + (cl-delete-duplicates + (org-element-map + (plist-get info :parse-tree) + '(src-block inline-src-block) + (lambda (src) + (plist-get + (org-export-read-attribute :attr_latex src) + :engraved-theme)) + info))) + (gen-theme-spec + (lambda (theme) + (if (eq engrave-faces-latex-output-style 'preset) + (engrave-faces-latex-gen-preamble (when theme (intern theme))) + (engrave-faces-latex-gen-preamble-line + 'default + (alist-get 'default + (if theme + (engrave-faces-get-theme (intern theme)) + engrave-faces-current-preset-style))))))) (when (string-match "^[ \t]*\\[FVEXTRA-SETUP\\][ \t]*\n?" engraved-preamble) (setq engraved-preamble (replace-match @@ -1315,10 +1335,31 @@ (defun org-latex-generate-engraved-preamble (info syntax-colours-p) (concat "\n% Setup for code blocks [1/2]\n\n" engraved-preamble - "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n" + "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n\n" (if (require 'engrave-faces-latex nil t) - (engrave-faces-latex-gen-preamble - (when engraved-theme (intern engraved-theme))) + (if engraved-themes + (concat + (mapconcat + (lambda (theme) + (format + "\n\\newcommand{\\engravedtheme%s}{%%\n%s\n}" + (replace-regexp-in-string "[^A-Za-z]" "" theme) + (replace-regexp-in-string + "newcommand" "renewcommand" + (replace-regexp-in-string + "#" "##" + (funcall gen-theme-spec theme))))) + engraved-themes + "\n") + "\n\n" + (cond + ((memq engraved-theme engraved-themes) + (concat "\\engravedtheme" + (replace-regexp-in-string + "[^A-Za-z]" "" engraved-theme) + "\n")) + (t (funcall gen-theme-spec engraved-theme)))) + (funcall gen-theme-spec engraved-theme)) (message "Cannot engrave source blocks. Consider installing `engrave-faces'.") "% WARNING syntax highlighting unavailible as engrave-faces-latex was missing.\n") "\n") @@ -2361,10 +2402,11 @@ (defun org-latex-inline-src-block--minted (info code lang) mint-lang code))) -(defun org-latex-inline-src-block--engraved (_info code lang) +(defun org-latex-inline-src-block--engraved (info code lang) "Transcode an inline src block's content from Org to LaTeX, using engrave-faces. INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." - (format "\\Verb{%s}" (org-latex-src--engrave-code code lang))) + (org-latex-src--engrave-code + code lang nil (plist-get info :latex-engraved-options) t)) (defun org-latex-inline-src-block--listings (info code lang) "Transcode an inline src block's content from Org to LaTeX, using lstlistings. @@ -3349,13 +3391,18 @@ (cl-defun org-latex-src-block--minted ;; Return value. (format float-env body))) -(defun org-latex-src--engrave-code (content lang) - "Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result." +(defun org-latex-src--engrave-code (content lang &optional theme options inline) + "Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result. +When THEME is non-nil, it will be used." (if (require 'engrave-faces-latex nil t) (let* ((lang-mode (and lang (org-src-get-lang-mode lang))) + (engrave-faces-current-preset-style + (if theme + (engrave-faces-get-theme theme) + engrave-faces-current-preset-style)) (engraved-buffer (with-temp-buffer - (insert content) + (insert (string-trim-right content "\n")) (when lang-mode (if (functionp lang-mode) (funcall lang-mode) @@ -3364,9 +3411,27 @@ (defun org-latex-src--engrave-code (content lang) (engrave-faces-latex-buffer))) (engraved-code (with-current-buffer engraved-buffer - (buffer-string)))) + (buffer-string))) + (engraved-options + (when options + (concat "[" + (if (listp options) + (org-latex--make-option-string options) + options) + "]"))) + (engraved-wrapped + (if inline + (concat "\\Verb" engraved-options "{" engraved-code "}") + (concat "\\begin{Code}\\begin{Verbatim}" engraved-options "\n" + engraved-code "\n\\end{Verbatim}\n\\end{Code}")))) (kill-buffer engraved-buffer) - engraved-code) + (if theme + (concat "{\\engravedtheme" + (replace-regexp-in-string "[^A-Za-z]" "" + (symbol-name theme)) + engraved-wrapped + "}") + engraved-wrapped)) (user-error "Cannot engrave code as `engrave-faces-latex' is unavailible."))) (cl-defun org-latex-src-block--engraved @@ -3394,7 +3459,15 @@ (cl-defun org-latex-src-block--engraved placement) "%s\n\\end{listing}")) (t "%s"))) - (options (plist-get info :latex-engraved-options)) + (options + (let ((engraved-options (plist-get info :latex-engraved-options)) + (local-options (plist-get attributes :options))) + (append + (when (and num-start (not (assoc "linenos" engraved-options))) + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start))))) + (and local-options (list local-options))))) + (engraved-theme (plist-get attributes :engraved-theme)) (content (let* ((code-info (org-export-unravel-code src-block)) (max-width @@ -3416,18 +3489,10 @@ (cl-defun org-latex-src-block--engraved (format "(%s)" ref))))) nil (and retain-labels (cdr code-info))))) (body - (format - "\\begin{Code}\n\\begin{Verbatim}[%s]\n%s\\end{Verbatim}\n\\end{Code}" - ;; Options. - (concat - (org-latex--make-option-string - (append - (when (and num-start (not (assoc "linenos" options))) - `(("linenos") - ("firstnumber" ,(number-to-string (1+ num-start))))) - (let ((local-options (plist-get attributes :options))) - (and local-options (list local-options)))))) - (org-latex-src--engrave-code content lang)))) + (org-latex-src--engrave-code + content lang + (when engraved-theme (intern engraved-theme)) + options))) (format float-env body))) (cl-defun org-latex-src-block--listings -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #11: 0010-ox-latex-Fix-captions-in-minted-engraved-code.patch --] [-- Type: text/x-patch, Size: 4986 bytes --] From ec560f6f037b902d603e9f34bbe593cb4c6bf4a9 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Mon, 9 May 2022 00:04:10 +0800 Subject: [PATCH 10/10] ox-latex: Fix %-captions in minted/engraved code * lisp/ox-latex.el (org-latex-src-block--engraved, org-latex-src-block--minted): Refactor float-env to be clearer, and switch from `format' to `concat' to fix the bug where %-chars in captions are interpreted as a format specifier. --- lisp/ox-latex.el | 55 +++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 528243a59..bb8072230 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -3332,23 +3332,20 @@ (cl-defun org-latex-src-block--minted (let* ((caption-str (org-latex--caption/label-string src-block info)) (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) (plist-get info :latex-default-figure-position))) + (multicolumn-p (string= "multicolumn" float)) (float-env (cond - ((string= "multicolumn" float) - (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - (caption - (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) + ((or caption multicolumn-p) + (cons + (concat "\\begin{listing" (when multicolumn-p "*") + "}[" placement "]\n" + (if caption-above-p caption-str "")) + (concat "\n" (if caption-above-p "" caption-str) + "\\end{listing" (when multicolumn-p "*") "}"))) ((string= "t" float) - (concat (format "\\begin{listing}[%s]\n" - placement) - "%s\n\\end{listing}")) - (t "%s"))) + (cons + (concat "\\begin{listing}[" placement "]\n") + "\n\\end{listing}")))) (options (plist-get info :latex-minted-options)) (body (format @@ -3388,8 +3385,7 @@ (cl-defun org-latex-src-block--minted ?\s) (format "(%s)" ref))))) nil (and retain-labels (cdr code-info))))))) - ;; Return value. - (format float-env body))) + (concat (car float-env) body (cdr float-env)))) (defun org-latex-src--engrave-code (content lang &optional theme options inline) "Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result. @@ -3442,23 +3438,20 @@ (cl-defun org-latex-src-block--engraved (let* ((caption-str (org-latex--caption/label-string src-block info)) (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) (plist-get info :latex-default-figure-position))) + (multicolumn-p (string= "multicolumn" float)) (float-env (cond - ((string= "multicolumn" float) - (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - (caption - (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) + ((or caption multicolumn-p) + (cons + (concat "\\begin{listing" (when multicolumn-p "*") + "}[" placement "]\n" + (if caption-above-p caption-str "")) + (concat "\n" (if caption-above-p "" caption-str) + "\\end{listing" (when multicolumn-p "*") "}"))) ((string= "t" float) - (concat (format "\\begin{listing}[%s]\n" - placement) - "%s\n\\end{listing}")) - (t "%s"))) + (cons + (concat "\\begin{listing}[" placement "]\n") + "\n\\end{listing}")))) (options (let ((engraved-options (plist-get info :latex-engraved-options)) (local-options (plist-get attributes :options))) @@ -3493,7 +3486,7 @@ (cl-defun org-latex-src-block--engraved content lang (when engraved-theme (intern engraved-theme)) options))) - (format float-env body))) + (concat (car float-env) body (cdr float-env)))) (cl-defun org-latex-src-block--listings (&key src-block info lang caption caption-above-p label num-start retain-labels attributes float &allow-other-keys) -- 2.35.3 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH] (v2) New LaTeX code export option: engraved 2022-05-08 14:30 ` [PATCH] (v2) " Timothy @ 2022-05-09 6:20 ` Ihor Radchenko 2022-05-09 12:57 ` Timothy 2022-05-11 16:05 ` [PATCH] (v3) " Timothy 1 sibling, 1 reply; 27+ messages in thread From: Ihor Radchenko @ 2022-05-09 6:20 UTC (permalink / raw) To: Timothy; +Cc: Daniel Fleischer, emacs-orgmode, Nicolas Goaziou Timothy <tecosaur@gmail.com> writes: > I have a new set of patches (attached), which make use of a major new feature in > engrave-faces v0.3: engraved themes. Thanks! > Glad to hear you’ve been able to have a look over the patches. With the feedback > I’ve received here so far, if no issues come up in the next few days I’m > inclined to merge this, add documentation, and see what feedback pops > up. Before merging, could you also try to implement tests at least for engraved feature? If I recall correctly, we do not currently have backend-specific tests. But it would certainly help if we did. You might as well write a small "nucleus" test for ox-latex. Also, unless I miss something, there is no support for coderefs in the patchset. Is it intentional? > +(defun org-latex-src-block--verbatim > ... > + (let ((caption-str (org-latex--caption/label-string src-block info)) > +(defun org-latex-src-block--custom > ... > + (let ((caption-str (org-latex--caption/label-string src-block info)) > + (formatted-src (org-export-format-code-default src-block info))) It appears that the code for caption-str is duplicated. It could be also factored out. > + (format-spec custom-env > + `((?s . ,formatted-src) > + (?c . ,caption) > + (?f . ,float) > + (?l . ,(org-latex--label src-block info)) > + (?o . ,(or (plist-get attributes :options) ""))))))) I do not see a definition of `format-spec' function. There is only `spec' above in the code. Can you double check? Either I am missing something or something fishy is going on. > + (let ((code (org-element-property :value inline-src-block)) > + (lang (org-element-property :language inline-src-block))) > + (pcase (plist-get info :latex-listings) > + ('nil (org-latex--text-markup code 'code info)) > + ('minted (org-latex-inline-src-block--minted info code lang)) > + (_ (org-latex-inline-src-block--listings info code lang))))) Please use `nil and `minted. Using ' may create issues in older Emacs. > +% In case engrave-faces-latex-gen-preamble has not been run. > +\\providecolor{EfD}{HTML}{f7f7f7} > +\\providecolor{EFD}{HTML}{28292e} What is the difference between EfD and EFD? EfD is also not documented. > +FVEXTRA-SETUP sets fvextra's defaults according to > +`org-latex-engraved-options', and LISTINGS-SETUP creates the > +listings environment and defines \\listoflistings." It is unclear what listings environment does given that we use engraved package. Can you provide a bit more details in the docstring on what the user will get if [LISTINGS-SETUP] is present. It may catch users by surprise that deleting this will make captions disappear. > @@ -1756,6 +1929,17 @@ (defun org-latex-template (contents info) > (let ((template (plist-get info :latex-hyperref-template))) > (and (stringp template) > (format-spec template spec))) > + ;; engrave-faces-latex preamble > + (when (eq org-latex-listings 'engraved) > + (let ((src-p (org-element-map (plist-get info :parse-tree) > + '(src-block inline-src-block) #'identity > + info t)) > + (fixedw-p > + (org-element-map (plist-get info :parse-tree) > + '(example-block fixed-width) #'identity > + info t))) > + (when (or src-p fixedw-p) > + (org-latex-generate-engraved-preamble info src-p)))) Why not just (org-element-map (plist-get info :parse-tree) '(src-block inline-src-block example-block fixed-width) #'identity info t) ? > (pcase (plist-get info :latex-listings) > ('nil (org-latex--text-markup code 'code info)) > ('minted (org-latex-inline-src-block--minted info code lang)) > + ('engraved (org-latex-inline-src-block--engraved info code lang)) > (_ (org-latex-inline-src-block--listings info code lang))))) Same comment about ` in pcase. > (defun org-latex-inline-src-block--listings (info code lang) > "Transcode an inline src block's content from Org to LaTeX, using lstlistings. > INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." > @@ -2323,6 +2513,7 @@ (defun org-latex-keyword (keyword _contents info) > (cl-case (plist-get info :latex-listings) > ((nil) "\\listoffigures") > (minted "\\listoflistings") > + (engraved "\\listoflistings") > (otherwise "\\lstlistoflistings"))))))))) What will happen if there is no [LISTINGS-SETUP]? > +(defcustom org-latex-engraved-theme nil > + "The theme that should be used for engraved code, when non-nil. > +This can be set to any theme defined in `engrave-faces-themes' or > +loadable by Emacs. When set to t, the current Emacs theme is > +used." > + :group 'org-export-latex > + :type 'symbol) Docstring does not explain what happens when set to nil. Also, does :type 'symbol allow t and nil? > - (engrave-faces-latex-gen-preamble) > + (engrave-faces-latex-gen-preamble > + (when engraved-theme (intern engraved-theme))) Will it work when engraved-theme is t? > - (engraved-theme (plist-get info :latex-engraved-theme))) > + (engraved-theme (plist-get info :latex-engraved-theme)) > + (engraved-themes > + (cl-delete-duplicates > + (org-element-map > + (plist-get info :parse-tree) > + '(src-block inline-src-block) > + (lambda (src) > + (plist-get > + (org-export-read-attribute :attr_latex src) > + :engraved-theme)) > + info))) What about example-block and fixed-width? I may be missing something, but earlier in the patchset you had conditionals of the type (or src-p fixedw-p). So, does engrave-faces do anything with fixedw-type elements? > + (gen-theme-spec > + (lambda (theme) > + (if (eq engrave-faces-latex-output-style 'preset) > + (engrave-faces-latex-gen-preamble (when theme (intern theme))) > + (engrave-faces-latex-gen-preamble-line > + 'default > + (alist-get 'default > + (if theme > + (engrave-faces-get-theme (intern theme)) > + engrave-faces-current-preset-style))))))) This appears to be not guarded by (require 'engrave-faces-latex nil t). > -(defun org-latex-src--engrave-code (content lang) > - "Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result." > +(defun org-latex-src--engrave-code (content lang &optional theme options inline) > + "Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result. > +When THEME is non-nil, it will be used." You did not document the remaining two arguments. (this makes me ask a question whether you checked compile warnings). Also, consider running M-x checkdoc on ox-latex.el. > - (insert content) > + (insert (string-trim-right content "\n")) As a theoretical possibility, what will happen if content has something like "%\n"? Best, Ihor ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] (v2) New LaTeX code export option: engraved 2022-05-09 6:20 ` Ihor Radchenko @ 2022-05-09 12:57 ` Timothy 2022-05-10 8:00 ` Max Nikulin 2022-05-11 11:06 ` Ihor Radchenko 0 siblings, 2 replies; 27+ messages in thread From: Timothy @ 2022-05-09 12:57 UTC (permalink / raw) To: Ihor Radchenko; +Cc: Daniel Fleischer, emacs-orgmode, Nicolas Goaziou [-- Attachment #1: Type: text/plain, Size: 5007 bytes --] Hi Ihor, > Before merging, could you also try to implement tests at least for > engraved feature? If I recall correctly, we do not currently have > backend-specific tests. But it would certainly help if we did. You might > as well write a small “nucleus” test for ox-latex. Probably not a bad idea, I’m just not sure what/how I’d go about this. > Also, unless I miss something, there is no support for coderefs in the > patchset. Is it intentional? I think you’ve missed something. It has the same coderefs support as minted. > It appears that the code for caption-str is duplicated. It could be > also factored out. It could, but I’m not sure this is actually a good idea as the duplication is more the result of chance than a common dependency. >> + (format-spec custom-env >> + `((?s . ,formatted-src) >> + (?c . ,caption) >> + (?f . ,float) >> + (?l . ,(org-latex–label src-block info)) >> + (?o . ,(or (plist-get attributes :options) “”))))))) > > I do not see a definition of `format-spec’ function. There is only > `spec’ above in the code. Can you double check? Either I am missing > something or something fishy is going on. This code isn’t introduced by my patches, just relocated. FWIW `format-spec' is provided by Emacs, and I don’t think is new. >> + (let ((code (org-element-property :value inline-src-block)) >> + (lang (org-element-property :language inline-src-block))) >> + (pcase (plist-get info :latex-listings) >> + (’nil (org-latex–text-markup code ’code info)) >> + (’minted (org-latex-inline-src-block–minted info code lang)) >> + (_ (org-latex-inline-src-block–listings info code lang))))) > > Please use `nil and `minted. Using ’ may create issues in older Emacs. Done. >> +% In case engrave-faces-latex-gen-preamble has not been run. >> +\ >> +\ > > What is the difference between EfD and EFD? EfD is also not documented. Documentation added. EfD is the background colour. >> +FVEXTRA-SETUP sets fvextra’s defaults according to >> +`org-latex-engraved-options’, and LISTINGS-SETUP creates the >> +listings environment and defines \.“ > > It is unclear what listings environment does given that we use engraved > package. Can you provide a bit more details in the docstring on what the > user will get if [LISTINGS-SETUP] is present. > It may catch users by surprise that deleting this will make captions > disappear. It does the same thing as minted’s `listings' environment, hence the choice of name. Documentation added. > Why not just > (org-element-map (plist-get info :parse-tree) > ’(src-block inline-src-block example-block fixed-width) #’identity > info t) Ah, in my config I’m also using some engraved info for example/fixed-width blocks. I’ll leave this out for now. >> (pcase (plist-get info :latex-listings) >> (’nil (org-latex–text-markup code ’code info)) >> … > Same comment about ` in pcase. Done. > What will happen if there is no [LISTINGS-SETUP]? Captioned/Floating code blocks won’t work. >> +(defcustom org-latex-engraved-theme nil > Docstring does not explain what happens when set to nil. > Also, does :type ’symbol allow t and nil? I think so, `symbolp' says they’re symbols if nothing else. > Will it work when engraved-theme is t? Yes. > What about example-block and fixed-width? I may be missing something, > but earlier in the patchset you had conditionals of the type > (or src-p fixedw-p). So, does engrave-faces do anything with fixedw-type > elements? Resolved earlier. >> + (gen-theme-spec >> + (lambda (theme) … > > This appears to be not guarded by (require ’engrave-faces-latex nil t). It is before it’s actually called. >> -(defun org-latex-src–engrave-code (content lang) >> - “Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result.” >> +(defun org-latex-src–engrave-code (content lang &optional theme options inline) >> + “Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result. >> +When THEME is non-nil, it will be used.” > > You did not document the remaining two arguments. (this makes me ask a > question whether you checked compile warnings). Also, consider running > M-x checkdoc on ox-latex.el. Now documented. I have checked compile warnings (there are none), but checkdoc is currently a bit dodgy on the Emacs commit I’m on. >> - (insert content) >> + (insert (string-trim-right content “”)) > > As a theoretical possibility, what will happen if content has something > like “%”? Discussed in DMs. It just gets rid of trailing newlines, and it’s fine with escaping. All the best, Timothy ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] (v2) New LaTeX code export option: engraved 2022-05-09 12:57 ` Timothy @ 2022-05-10 8:00 ` Max Nikulin 2022-05-11 11:06 ` Ihor Radchenko 1 sibling, 0 replies; 27+ messages in thread From: Max Nikulin @ 2022-05-10 8:00 UTC (permalink / raw) To: emacs-orgmode On 09/05/2022 19:57, Timothy wrote: > >> Before merging, could you also try to implement tests at least for >> engraved feature? If I recall correctly, we do not currently have >> backend-specific tests. But it would certainly help if we did. You might >> as well write a small “nucleus” test for ox-latex. > > Probably not a bad idea, I’m just not sure what/how I’d go about this. Have a look at `test-org-export/latex-src-block-verbatim-caption' in testing/lisp/test-ox.el Implementation is not perfect though. P.S. Feel free to ignore the following case. It is more related to #+begin_example block, but since it is too rigid, maybe it could be handled by #+begin_src with custom environment just to pass option argument to \begin{verbatim}. It may be considered as a probe if the code after refactoring is flexible enough to handle close use cases. Pedro Andres Aranda Gutierrez to emacs-orgmode. A question/bug report(?) Wed, 30 Mar 2022 07:14:54 +0200. https://list.orgmode.org/CAO48Bk_dJs1=5zgpcZwODaTsRqyRsKq1ALj6WpaXCc4bDjW3FQ@mail.gmail.com ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] (v2) New LaTeX code export option: engraved 2022-05-09 12:57 ` Timothy 2022-05-10 8:00 ` Max Nikulin @ 2022-05-11 11:06 ` Ihor Radchenko 1 sibling, 0 replies; 27+ messages in thread From: Ihor Radchenko @ 2022-05-11 11:06 UTC (permalink / raw) To: Timothy; +Cc: Daniel Fleischer, emacs-orgmode, Nicolas Goaziou Timothy <tecosaur@gmail.com> writes: Thanks for the replies. I consider all but one as resolved. >> What will happen if there is no [LISTINGS-SETUP]? > > Captioned/Floating code blocks won’t work. Can you also add this to the documentation of the preamble variable? Otherwise, it may not be very clear what inclusion/removal of [LISTINGS-SETUP] does. Best, Ihor ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] (v3) New LaTeX code export option: engraved 2022-05-08 14:30 ` [PATCH] (v2) " Timothy 2022-05-09 6:20 ` Ihor Radchenko @ 2022-05-11 16:05 ` Timothy 2022-05-12 16:40 ` Daniel Fleischer 1 sibling, 1 reply; 27+ messages in thread From: Timothy @ 2022-05-11 16:05 UTC (permalink / raw) To: Daniel Fleischer; +Cc: Ihor Radchenko, emacs-orgmode, Nicolas Goaziou [-- Attachment #1: Type: text/plain, Size: 799 bytes --] Hi All, I now have what I hope is the final set of patches[1]. Compared to v2 we have: • a fix for % in captions (long standing bug) • support for mathescaped code • a news/manual entry for engraved • a collection of tweaks based on Ihor’s lovely feedback 🤗 I’ve also slipped in a patch to `org-latex--label' which adds the `lst:' prefix (short for listings) to `\label's generated for source blocks. This seemed like a decent idea while I was working on captions, if anyone thinks otherwise I’ll happily leave it out. Daniel, if you’re happy with these commits let me know and I’ll push them :) All the best, Timothy Footnotes ───────── [1] For getting this feature into Org. I’m sure there will be tweaks in the future. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-ox-latex-Refactor-org-latex-src-block.patch --] [-- Type: text/x-patch, Size: 15944 bytes --] From 18adbd0e1226cf3307090861e09e92bfa9cdfbf1 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 14:35:34 +0800 Subject: [PATCH 01/13] ox-latex: Refactor `org-latex-src-block' * lisp/ox-latex.el (org-latex-src-block): Extract the per-format logic from `org-latex-src-block' into new dedicated functions: + `org-latex-src-block--verbatim' + `org-latex-src-block--custom' + `org-latex-src-block--minted' + `org-latex-src-block--listings' This makes `org-latex-src-block' much less monolithic, taking it from 175 lines to 30, and I find also makes it easier to understand. --- lisp/ox-latex.el | 339 ++++++++++++++++++++++++++--------------------- 1 file changed, 185 insertions(+), 154 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 841ad48bc..c2f728a1c 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2997,164 +2997,195 @@ (defun org-latex-src-block (src-block _contents info) (float (plist-get attributes :float)) (listings (plist-get info :latex-listings))) (cond - ;; Case 1. No source fontification. ((or (not lang) (not listings)) - (let ((caption-str (org-latex--caption/label-string src-block info)) - (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" - (org-export-format-code-default src-block info)))) - (cond ((string= "multicolumn" float) - (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" - (plist-get info :latex-default-figure-position) - (if caption-above-p caption-str "") - verbatim - (if caption-above-p "" caption-str))) - (caption (concat - (if caption-above-p caption-str "") - verbatim - (if caption-above-p "" (concat "\n" caption-str)))) - (t verbatim)))) - ;; Case 2. Custom environment. + (org-latex-src-block--verbatim src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) (custom-env - (let ((caption-str (org-latex--caption/label-string src-block info)) - (formatted-src (org-export-format-code-default src-block info))) - (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) - (format "\\begin{%s}\n%s\\end{%s}\n" - custom-env - (concat (and caption-above-p caption-str) - formatted-src - (and (not caption-above-p) caption-str)) - custom-env) - (format-spec custom-env - `((?s . ,formatted-src) - (?c . ,caption) - (?f . ,float) - (?l . ,(org-latex--label src-block info)) - (?o . ,(or (plist-get attributes :options) ""))))))) - ;; Case 3. Use minted package. + (org-latex-src-block--custom src-block info lang caption caption-above-p label + num-start retain-labels attributes float custom-env)) ((eq listings 'minted) - (let* ((caption-str (org-latex--caption/label-string src-block info)) - (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) - (plist-get info :latex-default-figure-position))) - (float-env - (cond - ((string= "multicolumn" float) - (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - (caption - (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - ((string= "t" float) - (concat (format "\\begin{listing}[%s]\n" - placement) - "%s\n\\end{listing}")) - (t "%s"))) - (options (plist-get info :latex-minted-options)) - (body - (format - "\\begin{minted}[%s]{%s}\n%s\\end{minted}" - ;; Options. - (concat - (org-latex--make-option-string - (if (or (not num-start) (assoc "linenos" options)) - options - (append - `(("linenos") - ("firstnumber" ,(number-to-string (1+ num-start)))) - options))) - (let ((local-options (plist-get attributes :options))) - (and local-options (concat "," local-options)))) - ;; Language. - (or (cadr (assq (intern lang) - (plist-get info :latex-minted-langs))) - (downcase lang)) - ;; Source code. - (let* ((code-info (org-export-unravel-code src-block)) - (max-width - (apply 'max - (mapcar 'length - (org-split-string (car code-info) - "\n"))))) - (org-export-format-code - (car code-info) - (lambda (loc _num ref) - (concat - loc - (when ref - ;; Ensure references are flushed to the right, - ;; separated with 6 spaces from the widest line - ;; of code. - (concat (make-string (+ (- max-width (length loc)) 6) - ?\s) - (format "(%s)" ref))))) - nil (and retain-labels (cdr code-info))))))) - ;; Return value. - (format float-env body))) - ;; Case 4. Use listings package. + (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) (t - (let ((lst-lang - (or (cadr (assq (intern lang) - (plist-get info :latex-listings-langs))) - lang)) - (caption-str - (when caption - (let ((main (org-export-get-caption src-block)) - (secondary (org-export-get-caption src-block t))) - (if (not secondary) - (format "{%s}" (org-export-data main info)) - (format "{[%s]%s}" - (org-export-data secondary info) - (org-export-data main info)))))) - (lst-opt (plist-get info :latex-listings-options))) - (concat - ;; Options. - (format - "\\lstset{%s}\n" - (concat - (org-latex--make-option-string - (append - lst-opt - (cond - ((and (not float) (plist-member attributes :float)) nil) - ((string= "multicolumn" float) '(("float" "*"))) - ((and float (not (assoc "float" lst-opt))) - `(("float" ,(plist-get info :latex-default-figure-position))))) - `(("language" ,lst-lang)) - (if label - `(("label" ,(org-latex--label src-block info))) - '(("label" " "))) - (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) - `(("captionpos" ,(if caption-above-p "t" "b"))) - (cond ((assoc "numbers" lst-opt) nil) - ((not num-start) '(("numbers" "none"))) - (t `(("firstnumber" ,(number-to-string (1+ num-start))) - ("numbers" "left")))))) - (let ((local-options (plist-get attributes :options))) - (and local-options (concat "," local-options))))) - ;; Source code. - (format - "\\begin{lstlisting}\n%s\\end{lstlisting}" - (let* ((code-info (org-export-unravel-code src-block)) - (max-width - (apply 'max - (mapcar 'length - (org-split-string (car code-info) "\n"))))) - (org-export-format-code - (car code-info) - (lambda (loc _num ref) - (concat - loc - (when ref - ;; Ensure references are flushed to the right, - ;; separated with 6 spaces from the widest line of - ;; code - (concat (make-string (+ (- max-width (length loc)) 6) ?\s) - (format "(%s)" ref))))) - nil (and retain-labels (cdr code-info)))))))))))) - + (org-latex-src-block--listings src-block info lang caption caption-above-p label + num-start retain-labels attributes float)))))) + +(defun org-latex-src-block--verbatim + (src-block info _lang caption caption-above-p _label + _num-start _retain-labels _attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using verbatim. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((caption-str (org-latex--caption/label-string src-block info)) + (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" + (org-export-format-code-default src-block info)))) + (cond ((string= "multicolumn" float) + (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" + (plist-get info :latex-default-figure-position) + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" caption-str))) + (caption (concat + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" (concat "\n" caption-str)))) + (t verbatim)))) + +(defun org-latex-src-block--custom + (src-block info _lang caption caption-above-p _label + _num-start _retain-labels attributes float custom-env) + "Transcode a SRC-BLOCK element from Org to LaTeX, using a custom environment. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((caption-str (org-latex--caption/label-string src-block info)) + (formatted-src (org-export-format-code-default src-block info))) + (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) + (format "\\begin{%s}\n%s\\end{%s}\n" + custom-env + (concat (and caption-above-p caption-str) + formatted-src + (and (not caption-above-p) caption-str)) + custom-env) + (format-spec custom-env + `((?s . ,formatted-src) + (?c . ,caption) + (?f . ,float) + (?l . ,(org-latex--label src-block info)) + (?o . ,(or (plist-get attributes :options) ""))))))) + +(defun org-latex-src-block--minted + (src-block info lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using minted. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-minted-options)) + (body + (format + "\\begin{minted}[%s]{%s}\n%s\\end{minted}" + ;; Options. + (concat + (org-latex--make-option-string + (if (or (not num-start) (assoc "linenos" options)) + options + (append + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start)))) + options))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options)))) + ;; Language. + (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase lang)) + ;; Source code. + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))))) + ;; Return value. + (format float-env body))) + +(defun org-latex-src-block--listings + (src-block info lang caption caption-above-p label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using listings. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let ((lst-lang + (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + lang)) + (caption-str + (when caption + (let ((main (org-export-get-caption src-block)) + (secondary (org-export-get-caption src-block t))) + (if (not secondary) + (format "{%s}" (org-export-data main info)) + (format "{[%s]%s}" + (org-export-data secondary info) + (org-export-data main info)))))) + (lst-opt (plist-get info :latex-listings-options))) + (concat + ;; Options. + (format + "\\lstset{%s}\n" + (concat + (org-latex--make-option-string + (append + lst-opt + (cond + ((and (not float) (plist-member attributes :float)) nil) + ((string= "multicolumn" float) '(("float" "*"))) + ((and float (not (assoc "float" lst-opt))) + `(("float" ,(plist-get info :latex-default-figure-position))))) + `(("language" ,lst-lang)) + (if label + `(("label" ,(org-latex--label src-block info))) + '(("label" " "))) + (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) + `(("captionpos" ,(if caption-above-p "t" "b"))) + (cond ((assoc "numbers" lst-opt) nil) + ((not num-start) '(("numbers" "none"))) + (t `(("firstnumber" ,(number-to-string (1+ num-start))) + ("numbers" "left")))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options))))) + ;; Source code. + (format + "\\begin{lstlisting}\n%s\\end{lstlisting}" + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line of + ;; code + (concat (make-string (+ (- max-width (length loc)) 6) ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info)))))))) ;;;; Statistics Cookie -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-ox-latex-Refactor-org-latex-inline-src-block.patch --] [-- Type: text/x-patch, Size: 4018 bytes --] From 6635b72356192c3b0be500984b327d0b4ebd8e2b Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 4 May 2022 18:53:10 +0800 Subject: [PATCH 02/13] ox-latex: Refactor `org-latex-inline-src-block' * lisp/ox-latex.el (org-latex-inline-src-block, org-latex-inline-src-block--minted, org-latex-inline-src-block--listings): Extract the minted and listings specific logic out of `org-latex-inline-src-block` into the new functions `org-latex-inline-src-block--minted` and `org-latex-inline-src-block--listings`. --- lisp/ox-latex.el | 62 +++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index c2f728a1c..38f36a1f3 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2127,36 +2127,38 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) "Transcode an INLINE-SRC-BLOCK element from Org to LaTeX. CONTENTS holds the contents of the item. INFO is a plist holding contextual information." - (let* ((code (org-element-property :value inline-src-block)) - (separator (org-latex--find-verb-separator code))) - (cl-case (plist-get info :latex-listings) - ;; Do not use a special package: transcode it verbatim, as code. - ((nil) (org-latex--text-markup code 'code info)) - ;; Use minted package. - (minted - (let* ((org-lang (org-element-property :language inline-src-block)) - (mint-lang (or (cadr (assq (intern org-lang) - (plist-get info :latex-minted-langs))) - (downcase org-lang))) - (options (org-latex--make-option-string - (plist-get info :latex-minted-options)))) - (format "\\mintinline%s{%s}{%s}" - (if (string= options "") "" (format "[%s]" options)) - mint-lang - code))) - ;; Use listings package. - (otherwise - ;; Maybe translate language's name. - (let* ((org-lang (org-element-property :language inline-src-block)) - (lst-lang (or (cadr (assq (intern org-lang) - (plist-get info :latex-listings-langs))) - org-lang)) - (options (org-latex--make-option-string - (append (plist-get info :latex-listings-options) - `(("language" ,lst-lang)))))) - (concat (format "\\lstinline[%s]" options) - separator code separator)))))) - + (let ((code (org-element-property :value inline-src-block)) + (lang (org-element-property :language inline-src-block))) + (pcase (plist-get info :latex-listings) + ('nil (org-latex--text-markup code 'code info)) + ('minted (org-latex-inline-src-block--minted info code lang)) + (_ (org-latex-inline-src-block--listings info code lang))))) + +(defun org-latex-inline-src-block--minted (info code lang) + "Transcode an inline src block's content from Org to LaTeX, using minted. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (let ((mint-lang (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase lang))) + (options (org-latex--make-option-string + (plist-get info :latex-minted-options)))) + (format "\\mintinline%s{%s}{%s}" + (if (string= options "") "" (format "[%s]" options)) + mint-lang + code))) + +(defun org-latex-inline-src-block--listings (info code lang) + "Transcode an inline src block's content from Org to LaTeX, using lstlistings. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (let* ((lst-lang (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + lang)) + (separator (org-latex--find-verb-separator code)) + (options (org-latex--make-option-string + (append (plist-get info :latex-listings-options) + `(("language" ,lst-lang)))))) + (concat (format "\\lstinline[%s]" options) + separator code separator))) ;;;; Inlinetask -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-ox-latex-More-versitile-option-construction.patch --] [-- Type: text/x-patch, Size: 4118 bytes --] From 108f321a80de89c72974fc25fcde36c85023daca Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 4 May 2022 23:31:59 +0800 Subject: [PATCH 03/13] ox-latex: More versitile option construction * lisp/ox-latex.el (org-latex--make-option-string): Support a custom option seperator string. (org-latex--make-option-string, org-latex-minted-options, org-latex-listings-options): The first line of the docstrings for `org-latex-minted-options` and `org-latex-listings-options` describe the variables as "association lists", yet `org-latex--make-option-string` does not handle association lists and an example of two-value lists is provided. To make the behaviour match the docstring, `org-latex--make-option-string` is modified to work with either a list two-value lists or an association list, and the examples in `org-latex-minted-options` and `org-latex-listings-options` updated accordingly. --- lisp/ox-latex.el | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 38f36a1f3..2d4b3bace 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -1006,12 +1006,16 @@ (defcustom org-latex-listings-options nil These options are supplied as a comma-separated list to the \\lstset command. Each element of the association list should be -a list containing two strings: the name of the option, and the -value. For example, +a list or cons cell containing two strings: the name of the +option, and the value. For example, (setq org-latex-listings-options \\='((\"basicstyle\" \"\\\\small\") (\"keywordstyle\" \"\\\\color{black}\\\\bfseries\\\\underbar\"))) + ; or + (setq org-latex-listings-options + \\='((\"basicstyle\" . \"\\\\small\") + (\"keywordstyle\" . \"\\\\color{black}\\\\bfseries\\\\underbar\"))) will typeset the code in a small size font with underlined, bold black keywords. @@ -1059,11 +1063,14 @@ (defcustom org-latex-minted-options nil These options are supplied within square brackets in \\begin{minted} environments. Each element of the alist should -be a list containing two strings: the name of the option, and the -value. For example, +be a list or cons cell containing two strings: the name of the +option, and the value. For example, (setq org-latex-minted-options \\='((\"bgcolor\" \"bg\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-minted-options + \\='((\"bgcolor\" . \"bg\") (\"frame\" . \"lines\"))) will result in source blocks being exported with @@ -1506,21 +1513,24 @@ (defun org-latex--find-verb-separator (s) when (not (string-match (regexp-quote (char-to-string c)) s)) return (char-to-string c)))) -(defun org-latex--make-option-string (options) +(defun org-latex--make-option-string (options &optional seperator) "Return a comma separated string of keywords and values. OPTIONS is an alist where the key is the options keyword as a string, and the value a list containing the keyword value, or nil." (mapconcat (lambda (pair) - (pcase-let ((`(,keyword ,value) pair)) - (concat keyword - (and (> (length value) 0) - (concat "=" - (if (string-match-p (rx (any "[]")) value) - (format "{%s}" value) - value)))))) - options - ",")) + (let ((keyword (car pair)) + (value (pcase (cdr pair) + ((pred stringp) (cdr pair)) + ((pred consp) (cadr pair))))) + (concat keyword + (when value + (concat "=" + (if (string-match-p (rx (any "[]")) value) + (format "{%s}" value) + value)))))) + options + (or seperator ","))) (defun org-latex--wrap-label (element output info) "Wrap label associated to ELEMENT around OUTPUT, if appropriate. -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-ox-latex-Introduce-engraved-code-highlighting.patch --] [-- Type: text/x-patch, Size: 17857 bytes --] From ac29f0f3991faf457f161698b4ad311edfe5d55d Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 21 Nov 2021 20:04:12 +0800 Subject: [PATCH 04/13] ox-latex: Introduce "engraved" code highlighting * lisp/ox-latex.el (org-latex-src-block, org-latex-src-block--engraved, org-latex-inline-src-block, org-latex-inline-src-block--engraved, org-latex-src--engrave-code, org-latex-template, org-latex-listings): Make use of the engraved-faces package (available on ELPA) to provide an alternative LaTeX code highlighting backend which functions similarly to htmlize.el for HTML exports. (org-latex-engraved-preamble, org-latex-engraved-options): Introduce variables to construct the preamble for engraved code blocks. * lisp/ox-beamer.el (org-beamer-template): Modify to add engrave-faces preamble when applicable. --- lisp/ox-beamer.el | 6 + lisp/ox-latex.el | 292 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 289 insertions(+), 9 deletions(-) diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 6be73c91e..fe73bf686 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -857,6 +857,12 @@ (defun org-beamer-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template (org-latex--format-spec info)))) + ;; engrave-faces-latex preamble + (when (and (eq org-latex-listings 'engraved) + (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity + info t)) + (org-latex-generate-engraved-preamble info t)) ;; Document start. "\\begin{document}\n\n" ;; Title command. diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 2d4b3bace..e0f47cf80 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -37,6 +37,8 @@ (defvar org-latex-default-packages-alist) (defvar org-latex-packages-alist) (defvar orgtbl-exp-regexp) +(declare-function engrave-faces-latex-gen-preamble "ext:engrave-faces-latex") +(declare-function engrave-faces-latex-buffer "ext:engrave-faces-latex") \f ;;; Define Back-End @@ -125,6 +127,8 @@ (org-export-define-backend 'latex (:latex-default-quote-environment nil nil org-latex-default-quote-environment) (:latex-default-table-mode nil nil org-latex-default-table-mode) (:latex-diary-timestamp-format nil nil org-latex-diary-timestamp-format) + (:latex-engraved-options nil nil org-latex-engraved-options) + (:latex-engraved-preamble nil nil org-latex-engraved-preamble) (:latex-footnote-defined-format nil nil org-latex-footnote-defined-format) (:latex-footnote-separator nil nil org-latex-footnote-separator) (:latex-format-drawer-function nil nil org-latex-format-drawer-function) @@ -937,22 +941,48 @@ (defcustom org-latex-listings nil "Non-nil means export source code using the listings package. This package will fontify source code, possibly even with color. -If you want to use this, you also need to make LaTeX use the -listings package, and if you want to have color, the color -package. Just add these to `org-latex-packages-alist', for -example using customize, or with something like: +There are four implementations of this functionality you may +choose from (ordered from least to most capable): +1. Verbatim (nil) +2. Listings (t) +3. Minted (minted) +4. Engraved (engraved) + +The first two options provide basic syntax +highlighting (listings), or none at all (verbatim). + +When using listings, you also need to make use of the LaTeX +\"listings\" package. The \"color\" package is also needed if you +would like color too. These can simply be added to +`org-latex-packages-alist', using customise or something like: (require \\='ox-latex) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"listings\")) (add-to-list \\='org-latex-packages-alist \\='(\"\" \"color\")) -Alternatively, +There are two further options for more comprehensive +fontification. The first can be set with, + + (setq org-latex-listings \\='engraved) + +which causes source code to be run through +`engrave-faces-latex-buffer', which generates colorings using +Emacs' font-lock information. This requires the engrave-faces +package (availible from ELPA), and the fvextra LaTeX package be +installed. + +The styling of the engraved result can customised with +`org-latex-engraved-preamble' and `org-latex-engraved-options'. +The default preamble also uses the tcolorbox LaTeX package in +addition to fvextra. + +The second more comprehensive option can be set with, (setq org-latex-listings \\='minted) -causes source code to be exported using the minted package as -opposed to listings. If you want to use minted, you need to add -the minted package to `org-latex-packages-alist', for example +which causes source code to be exported using the minted package +as opposed to listings. If you want to use minted, you need to +add the minted package to `org-latex-packages-alist', for example using customize, or with (require \\='ox-latex) @@ -971,8 +1001,9 @@ (defcustom org-latex-listings nil :type '(choice (const :tag "Use listings" t) (const :tag "Use minted" minted) + (const :tag "Use engrave-faces-latex" engraved) (const :tag "Export verbatim" nil)) - :safe (lambda (s) (memq s '(t nil minted)))) + :safe (lambda (s) (memq s '(t nil minted engraved)))) (defcustom org-latex-listings-langs '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp") @@ -1142,6 +1173,151 @@ (defcustom org-latex-custom-lang-environments nil :version "26.1" :package-version '(Org . "9.0")) +(defcustom org-latex-engraved-preamble + "\\usepackage{fvextra} + +[FVEXTRA-SETUP] + +% Make line numbers smaller and grey. +\\renewcommand\\theFancyVerbLine{\\footnotesize\\color{black!40!white}\\arabic{FancyVerbLine}} + +\\usepackage{xcolor} + +% In case engrave-faces-latex-gen-preamble has not been run. +\\providecolor{EfD}{HTML}{f7f7f7} +\\providecolor{EFD}{HTML}{28292e} + +% Define a Code environment to prettily wrap the fontified code. +\\usepackage[breakable,xparse]{tcolorbox} +\\DeclareTColorBox[]{Code}{o}% +{colback=EfD!98!EFD, colframe=EfD!95!EFD, + fontupper=\\footnotesize\\setlength{\\fboxsep}{0pt}, + colupper=EFD, + IfNoValueTF={#1}% + {boxsep=2pt, arc=2.5pt, outer arc=2.5pt, + boxrule=0.5pt, left=2pt}% + {boxsep=2.5pt, arc=0pt, outer arc=0pt, + boxrule=0pt, leftrule=1.5pt, left=0.5pt}, + right=2pt, top=1pt, bottom=0.5pt, + breakable} + +[LISTINGS-SETUP]" + "Preamble content injected when using engrave-faces-latex for source blocks. +This is relevant when `org-latex-listings' is set to `engraved'. + +There is quite a lot of flexibility in what this preamble can be, +as long as it: +- Loads the fvextra package. +- Loads the package xcolor (if it is not already loaded elsewhere). +- Defines a \"Code\" environment (note the capital C), which all + \"Verbatim\" environments (provided by fvextra) will be wrapped with. + +In the default value the colors \"EFD\" and \"EfD\" are provided +as they are respectively the foreground and background colours, +just in case they aren't provided by the generated preamble, so +we can asume they are always set. + +Within this preamble there are two recognised macro-like placeholders: + + [FVEXTRA-SETUP] + + [LISTINGS-SETUP] + +Unless you have a very good reason, both of these placeholders +should be included in the preamble. + +FVEXTRA-SETUP sets fvextra's defaults according to +`org-latex-engraved-options', and LISTINGS-SETUP creates the +listings environment used for captioned or floating code blocks, +as well as defining \\listoflistings." + :group 'org-export-latex + :type 'string + :package-version '(Org . "9.6")) + +(defcustom org-latex-engraved-options + '(("commandchars" . "\\\\\\{\\}") + ("highlightcolor" . "white!95!black!80!blue") + ("breaklines" . "true") + ("breaksymbol" . "\\color{white!60!black}\\tiny\\ensuremath{\\hookrightarrow}")) + "Association list of options for the latex fvextra package when engraving code. + +These options are set using \\fvset{...} in the preamble of the +LaTeX export. Each element of the alist should be a list or cons +cell containing two strings: the name of the option, and the +value. For example, + + (setq org-latex-engraved-options + \\='((\"highlightcolor\" \"green\") (\"frame\" \"lines\"))) + ; or + (setq org-latex-engraved-options + \\='((\"highlightcolor\" . \"green\") (\"frame\" . \"lines\"))) + +will result in the following LaTeX in the preamble + +\\fvset{% + bgcolor=bg, + frame=lines} + +This will affect all fvextra environments. Note that the same +options will be applied to all blocks. If you need +block-specific options, you may use the following syntax: + + #+ATTR_LATEX: :options key1=value1,key2=value2 + #+BEGIN_SRC <LANG> + ... + #+END_SRC" + :group 'org-export-latex + :type '(alist :key-type (string :tag "option") + :value-type (string :tag "value"))) + +(defun org-latex-generate-engraved-preamble (info syntax-colours-p) + "Generate the preamble to setup engraved code. +The result is constructed from the :latex-engraved-preamble and +:latex-engraved-optionsn export options, the default values of +which are given by `org-latex-engraved-preamble' and +`org-latex-engraved-options' respectively." + (let* ((engraved-options + (plist-get info :latex-engraved-options)) + (engraved-preamble (plist-get info :latex-engraved-preamble))) + (when (string-match "^[ \t]*\\[FVEXTRA-SETUP\\][ \t]*\n?" engraved-preamble) + (setq engraved-preamble + (replace-match + (concat + "\\fvset{%\n " + (org-latex--make-option-string engraved-options ",\n ") + "}\n") + t t + engraved-preamble))) + (when (string-match "^[ \t]*\\[LISTINGS-SETUP\\][ \t]*\n?" engraved-preamble) + (setq engraved-preamble + (replace-match + (format + "%% Support listings with captions +\\usepackage{float} +\\floatstyle{%s} +\\newfloat{listing}{htbp}{lst} +\\newcommand{\\listingsname}{Listing} +\\floatname{listing}{\\listingsname} +\\newcommand{\\listoflistingsname}{List of Listings} +\\providecommand{\\listoflistings}{\\listof{listing}{\\listoflistingsname}}\n" + (if (memq 'src-block org-latex-caption-above) + "plaintop" "plain")) + t t + engraved-preamble))) + (if syntax-colours-p + (concat + "\n% Setup for code blocks [1/2]\n\n" + engraved-preamble + "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n" + (if (require 'engrave-faces-latex nil t) + (engrave-faces-latex-gen-preamble) + (message "Cannot engrave source blocks. Consider installing `engrave-faces'.") + "% WARNING syntax highlighting unavailible as engrave-faces-latex was missing.\n") + "\n") + (concat + "\n% Setup for code blocks\n\n" + engraved-preamble + "\n")))) ;;;; Compilation @@ -1756,6 +1932,12 @@ (defun org-latex-template (contents info) (let ((template (plist-get info :latex-hyperref-template))) (and (stringp template) (format-spec template spec))) + ;; engrave-faces-latex preamble + (when (and (eq org-latex-listings 'engraved) + (org-element-map (plist-get info :parse-tree) + '(src-block inline-src-block) #'identity + info t)) + (org-latex-generate-engraved-preamble info t)) ;; Document start. "\\begin{document}\n\n" ;; Title command. @@ -2142,6 +2324,7 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) (pcase (plist-get info :latex-listings) ('nil (org-latex--text-markup code 'code info)) ('minted (org-latex-inline-src-block--minted info code lang)) + ('engraved (org-latex-inline-src-block--engraved info code lang)) (_ (org-latex-inline-src-block--listings info code lang))))) (defun org-latex-inline-src-block--minted (info code lang) @@ -2157,6 +2340,11 @@ (defun org-latex-inline-src-block--minted (info code lang) mint-lang code))) +(defun org-latex-inline-src-block--engraved (_info code lang) + "Transcode an inline src block's content from Org to LaTeX, using engrave-faces. +INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." + (format "\\Verb{%s}" (org-latex-src--engrave-code code lang))) + (defun org-latex-inline-src-block--listings (info code lang) "Transcode an inline src block's content from Org to LaTeX, using lstlistings. INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." @@ -2323,6 +2511,7 @@ (defun org-latex-keyword (keyword _contents info) (cl-case (plist-get info :latex-listings) ((nil) "\\listoffigures") (minted "\\listoflistings") + (engraved "\\listoflistings") (otherwise "\\lstlistoflistings"))))))))) @@ -3017,6 +3206,9 @@ (defun org-latex-src-block (src-block _contents info) num-start retain-labels attributes float custom-env)) ((eq listings 'minted) (org-latex-src-block--minted src-block info lang caption caption-above-p label + num-start retain-labels attributes float)) + ((eq listings 'engraved) + (org-latex-src-block--engraved src-block info lang caption caption-above-p label num-start retain-labels attributes float)) (t (org-latex-src-block--listings src-block info lang caption caption-above-p label @@ -3133,6 +3325,88 @@ (defun org-latex-src-block--minted ;; Return value. (format float-env body))) +(defun org-latex-src--engrave-code (content lang) + "Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result." + (if (require 'engrave-faces-latex nil t) + (let* ((lang-mode (and lang (org-src-get-lang-mode lang))) + (engraved-buffer + (with-temp-buffer + (insert content) + (when lang-mode + (if (functionp lang-mode) + (funcall lang-mode) + (message "Cannot engrave code as %s. %s is undefined." + lang lang-mode))) + (engrave-faces-latex-buffer))) + (engraved-code + (with-current-buffer engraved-buffer + (buffer-string)))) + (kill-buffer engraved-buffer) + engraved-code) + (user-error "Cannot engrave code as `engrave-faces-latex' is unavailible."))) + +(defun org-latex-src-block--engraved + (src-block info lang caption caption-above-p _label + num-start retain-labels attributes float) + "Transcode a SRC-BLOCK element from Org to LaTeX, using engrave-faces-latex. +LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES +and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-engraved-options)) + (content + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'string-width + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))) + (body + (format + "\\begin{Code}\n\\begin{Verbatim}[%s]\n%s\\end{Verbatim}\n\\end{Code}" + ;; Options. + (concat + (org-latex--make-option-string + (append + (when (and num-start (not (assoc "linenos" options))) + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (list local-options)))))) + (org-latex-src--engrave-code content lang)))) + (format float-env body))) + (defun org-latex-src-block--listings (src-block info lang caption caption-above-p label num-start retain-labels attributes float) -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: 0005-ox-latex-Don-t-use-length-to-get-string-width.patch --] [-- Type: text/x-patch, Size: 1539 bytes --] From 815de46384a566b3dcd86061b9aa93563a7acb29 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sat, 7 May 2022 13:59:13 +0800 Subject: [PATCH 05/13] ox-latex: Don't use `length' to get string width * lisp/ox-latex.el (org-latex-src-block--listings, org-latex-src-block--engraved, org-latex-src-block--minted): Use `string-width' instead of `length' to gauge the displayed width of the string in LaTeX. This may not be a perfect match, but it should be an improvement. --- lisp/ox-latex.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index e0f47cf80..0788b40c0 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -3306,7 +3306,7 @@ (defun org-latex-src-block--minted (let* ((code-info (org-export-unravel-code src-block)) (max-width (apply 'max - (mapcar 'length + (mapcar 'string-width (org-split-string (car code-info) "\n"))))) (org-export-format-code @@ -3458,7 +3458,7 @@ (defun org-latex-src-block--listings (let* ((code-info (org-export-unravel-code src-block)) (max-width (apply 'max - (mapcar 'length + (mapcar 'string-width (org-split-string (car code-info) "\n"))))) (org-export-format-code (car code-info) -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #7: 0006-ox-latex-Refactor-source-block-transcode-fun-sigs.patch --] [-- Type: text/x-patch, Size: 7299 bytes --] From fadf2011884d0e46b5442ec43dc942050e2fd048 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sat, 7 May 2022 14:02:44 +0800 Subject: [PATCH 06/13] ox-latex: Refactor source block transcode fun sigs * lisp/ox-latex.el (org-latex-src-block--listings, org-latex-src-block--engraved, org-latex-src-block--minted, org-latex-src-block--custom): Refactor these --backend functions to use cl-defun with keys instead of having an 11-argument signature. (org-latex-src-block): Adjust for the change in signature of the --backend functions, and refactor the `cond' statement to use `pcase'. --- lisp/ox-latex.el | 82 +++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 0788b40c0..4a077bb27 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -3186,37 +3186,37 @@ (defun org-latex-src-block (src-block _contents info) contextual information." (when (org-string-nw-p (org-element-property :value src-block)) (let* ((lang (org-element-property :language src-block)) - (caption (org-element-property :caption src-block)) - (caption-above-p (org-latex--caption-above-p src-block info)) - (label (org-element-property :name src-block)) - (custom-env (and lang - (cadr (assq (intern lang) - org-latex-custom-lang-environments)))) - (num-start (org-export-get-loc src-block info)) - (retain-labels (org-element-property :retain-labels src-block)) - (attributes (org-export-read-attribute :attr_latex src-block)) - (float (plist-get attributes :float)) - (listings (plist-get info :latex-listings))) - (cond - ((or (not lang) (not listings)) - (org-latex-src-block--verbatim src-block info lang caption caption-above-p label - num-start retain-labels attributes float)) - (custom-env - (org-latex-src-block--custom src-block info lang caption caption-above-p label - num-start retain-labels attributes float custom-env)) - ((eq listings 'minted) - (org-latex-src-block--minted src-block info lang caption caption-above-p label - num-start retain-labels attributes float)) - ((eq listings 'engraved) - (org-latex-src-block--engraved src-block info lang caption caption-above-p label - num-start retain-labels attributes float)) - (t - (org-latex-src-block--listings src-block info lang caption caption-above-p label - num-start retain-labels attributes float)))))) - -(defun org-latex-src-block--verbatim - (src-block info _lang caption caption-above-p _label - _num-start _retain-labels _attributes float) + (caption (org-element-property :caption src-block)) + (caption-above-p (org-latex--caption-above-p src-block info)) + (label (org-element-property :name src-block)) + (custom-env (and lang + (cadr (assq (intern lang) + org-latex-custom-lang-environments)))) + (num-start (org-export-get-loc src-block info)) + (retain-labels (org-element-property :retain-labels src-block)) + (attributes (org-export-read-attribute :attr_latex src-block)) + (float (plist-get attributes :float)) + (listings (plist-get info :latex-listings))) + (funcall + (pcase listings + ((or (pred not) (guard (not lang))) #'org-latex-src-block--verbatim) + ((guard custom-env) #'org-latex-src-block--custom) + ('minted #'org-latex-src-block--minted) + ('engraved #'org-latex-src-block--engraved) + (_ #'org-latex-src-block--listings)) + :src-block src-block + :info info + :lang lang + :caption caption + :caption-above-p caption-above-p + :label label + :num-start num-start + :retain-labels retain-labels + :attributes attributes + :float float)))) + +(cl-defun org-latex-src-block--verbatim + (&key src-block info caption caption-above-p float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using verbatim. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3235,9 +3235,8 @@ (defun org-latex-src-block--verbatim (if caption-above-p "" (concat "\n" caption-str)))) (t verbatim)))) -(defun org-latex-src-block--custom - (src-block info _lang caption caption-above-p _label - _num-start _retain-labels attributes float custom-env) +(cl-defun org-latex-src-block--custom + (&key src-block info caption caption-above-p attributes float custom-env &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using a custom environment. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3257,9 +3256,8 @@ (defun org-latex-src-block--custom (?l . ,(org-latex--label src-block info)) (?o . ,(or (plist-get attributes :options) ""))))))) -(defun org-latex-src-block--minted - (src-block info lang caption caption-above-p _label - num-start retain-labels attributes float) +(cl-defun org-latex-src-block--minted + (&key src-block info lang caption caption-above-p num-start retain-labels attributes float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using minted. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3345,9 +3343,8 @@ (defun org-latex-src--engrave-code (content lang) engraved-code) (user-error "Cannot engrave code as `engrave-faces-latex' is unavailible."))) -(defun org-latex-src-block--engraved - (src-block info lang caption caption-above-p _label - num-start retain-labels attributes float) +(cl-defun org-latex-src-block--engraved + (&key src-block info lang caption caption-above-p num-start retain-labels attributes float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using engrave-faces-latex. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." @@ -3407,9 +3404,8 @@ (defun org-latex-src-block--engraved (org-latex-src--engrave-code content lang)))) (format float-env body))) -(defun org-latex-src-block--listings - (src-block info lang caption caption-above-p label - num-start retain-labels attributes float) +(cl-defun org-latex-src-block--listings + (&key src-block info lang caption caption-above-p label num-start retain-labels attributes float &allow-other-keys) "Transcode a SRC-BLOCK element from Org to LaTeX, using listings. LANG, CAPTION, CAPTION-ABOVE-P, LABEL, NUM-START, RETAIN-LABELS, ATTRIBUTES and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'." -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #8: 0007-ox-latex-Replace-org-latex-listings.patch --] [-- Type: text/x-patch, Size: 16239 bytes --] From e6dfd941daf06beb859ae6effd0be9d734121897 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sat, 7 May 2022 14:46:28 +0800 Subject: [PATCH 07/13] ox-latex: Replace `org-latex-listings' * lisp/ox-latex.el (org-latex-src-block, org-latex-keyword, org-latex-inline-src-block, org-latex-template, org-latex--caption/label-string, org-latex-engraved-preamble, org-latex-listings): Replace `org-latex-listings' with `org-latex-src-block-backend', which now can be set to listings/verbatim and no longer advertises t/nil as valid values. * lisp/ox-beamer.el (org-beamer-template): Update in the same manner as `org-latex-template'. * lisp/org-compat.el: Make `org-latex-listings' an obsolete alias for `org-latex-src-block-backend'. * testing/lisp/test-ox.el: Replace `org-latex-listings' reference with `org-latex-src-block-backend'. * doc/org-manual.org (Footnotes, LaTeX specific properties, Literal Examples): Replace references to `org-latex-listings' with `org-latex-src-block-backend'. * etc/ORG-NEWS: Add a news entry noting this change. The variable `org-latex-listings' originally indicated whether source blocks should use the listings LaTeX package, or not. This usage has evolved over the years, and now it sets one of four different fontification backends. This renaming should make the variable name a bit less misleading. --- doc/org-manual.org | 6 +-- etc/ORG-NEWS | 9 ++++ lisp/org-compat.el | 2 + lisp/ox-beamer.el | 2 +- lisp/ox-latex.el | 117 ++++++++++++++++++++++------------------ testing/lisp/test-ox.el | 2 +- 6 files changed, 81 insertions(+), 57 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index c0d38cd8c..60bded419 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -11159,7 +11159,7 @@ ** Literal Examples #+end_example #+cindex: formatting source code, markup rules -#+vindex: org-latex-listings +#+vindex: org-latex-src-block-backend If the example is source code from a programming language, or any other text that can be marked up by Font Lock in Emacs, you can ask for the example to look like the fontified Emacs buffer[fn:114]. This @@ -16304,12 +16304,12 @@ **** LaTeX specific properties | ~:latex-link-with-unknown-path-format~ | ~org-latex-link-with-unknown-path-format~ | | ~:latex-listings-langs~ | ~org-latex-listings-langs~ | | ~:latex-listings-options~ | ~org-latex-listings-options~ | -| ~:latex-listings~ | ~org-latex-listings~ | | ~:latex-minted-langs~ | ~org-latex-minted-langs~ | | ~:latex-minted-options~ | ~org-latex-minted-options~ | | ~:latex-prefer-user-labels~ | ~org-latex-prefer-user-labels~ | | ~:latex-subtitle-format~ | ~org-latex-subtitle-format~ | | ~:latex-subtitle-separate~ | ~org-latex-subtitle-separate~ | +| ~:latex-src-block-backend~ | ~org-latex-src-block-backend~ | | ~:latex-table-scientific-notation~ | ~org-latex-table-scientific-notation~ | | ~:latex-tables-booktabs~ | ~org-latex-tables-booktabs~ | | ~:latex-tables-centered~ | ~org-latex-tables-centered~ | @@ -22256,7 +22256,7 @@ * Footnotes version 1.34 of the =htmlize.el= package, which you need to install). Fontified code chunks in LaTeX can be achieved using either the [[https://www.ctan.org/pkg/listings][listings]] package or the [[https://www.ctan.org/pkg/minted][minted]] package. Refer to -~org-latex-listings~ for details. +~org-latex-src-block-backend~ for details. [fn:115] Source code in code blocks may also be evaluated either interactively or on export. See [[*Working with Source Code]] for more diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 27de6da62..ebb3cd649 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -273,6 +273,15 @@ Chmod-style permissions are based on the new variable ~org-babel-tangle-default-file-mode~. *** A new custom setting =org-agenda-clock-report-header= to add a header to org agenda clock report + +*** ~org-latex-listings~ has been replaced with ~org-latex-src-block-backend~ + +~org-latex-listings~ has been renamed to better reflect the current +purpose of the variable. The replacement variable +~org-latex-src-block-backend~ acts in exactly the same way, however it +accepts =listings= and =verbatim= in place of =t= and =nil= (which +still work, but are no longer listed as valid options). + * Version 9.5 ** Important announcements and breaking changes diff --git a/lisp/org-compat.el b/lisp/org-compat.el index a29f206a4..704197645 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -324,6 +324,8 @@ (define-obsolete-variable-alias 'org-latex-create-formula-image-program 'org-preview-latex-default-process "9.0") (define-obsolete-variable-alias 'org-latex-preview-ltxpng-directory 'org-preview-latex-image-directory "9.0") +(define-obsolete-variable-alias 'org-latex-listings + 'org-latex-src-block-backend "9.6") (define-obsolete-function-alias 'org-table-p 'org-at-table-p "9.0") (define-obsolete-function-alias 'org-on-heading-p 'org-at-heading-p "9.0") (define-obsolete-function-alias 'org-at-regexp-p 'org-in-regexp "8.3") diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index fe73bf686..e6232d8d2 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -858,7 +858,7 @@ (defun org-beamer-template (contents info) (and (stringp template) (format-spec template (org-latex--format-spec info)))) ;; engrave-faces-latex preamble - (when (and (eq org-latex-listings 'engraved) + (when (and (eq org-latex-src-block-backend 'engraved) (org-element-map (plist-get info :parse-tree) '(src-block inline-src-block) #'identity info t)) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 4a077bb27..f81625b45 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -143,7 +143,7 @@ (org-export-define-backend 'latex (:latex-inactive-timestamp-format nil nil org-latex-inactive-timestamp-format) (:latex-inline-image-rules nil nil org-latex-inline-image-rules) (:latex-link-with-unknown-path-format nil nil org-latex-link-with-unknown-path-format) - (:latex-listings nil nil org-latex-listings) + (:latex-src-block-backend nil nil org-latex-src-block-backend) (:latex-listings-langs nil nil org-latex-listings-langs) (:latex-listings-options nil nil org-latex-listings-options) (:latex-minted-langs nil nil org-latex-minted-langs) @@ -937,22 +937,22 @@ (defcustom org-latex-format-inlinetask-function ;; Src blocks -(defcustom org-latex-listings nil - "Non-nil means export source code using the listings package. +(defcustom org-latex-src-block-backend 'verbatim + "Backend used to generate source code listings. -This package will fontify source code, possibly even with color. -There are four implementations of this functionality you may +This sets the behaviour for fontifying source code, possibly even with +color. There are four implementations of this functionality you may choose from (ordered from least to most capable): -1. Verbatim (nil) -2. Listings (t) -3. Minted (minted) -4. Engraved (engraved) +1. Verbatim +2. Listings +3. Minted +4. Engraved The first two options provide basic syntax highlighting (listings), or none at all (verbatim). -When using listings, you also need to make use of the LaTeX -\"listings\" package. The \"color\" package is also needed if you +When using listings, you also need to make use of LaTeX package +\"listings\"e. The \"color\" LaTeX package is also needed if you would like color too. These can simply be added to `org-latex-packages-alist', using customise or something like: @@ -963,27 +963,12 @@ (defcustom org-latex-listings nil There are two further options for more comprehensive fontification. The first can be set with, - (setq org-latex-listings \\='engraved) + (setq org-latex-src-block-backend \\='minted) -which causes source code to be run through -`engrave-faces-latex-buffer', which generates colorings using -Emacs' font-lock information. This requires the engrave-faces -package (availible from ELPA), and the fvextra LaTeX package be -installed. - -The styling of the engraved result can customised with -`org-latex-engraved-preamble' and `org-latex-engraved-options'. -The default preamble also uses the tcolorbox LaTeX package in -addition to fvextra. - -The second more comprehensive option can be set with, - - (setq org-latex-listings \\='minted) - -which causes source code to be exported using the minted package -as opposed to listings. If you want to use minted, you need to -add the minted package to `org-latex-packages-alist', for example -using customize, or with +which causes source code to be exported using the LaTeX package +minted as opposed to listings. If you want to use minted, you +need to add the minted package to `org-latex-packages-alist', for +example using customize, or with (require \\='ox-latex) (add-to-list \\='org-latex-packages-alist \\='(\"newfloat\" \"minted\")) @@ -996,14 +981,29 @@ (defcustom org-latex-listings nil The minted choice has possible repercussions on the preview of latex fragments (see `org-preview-latex-fragment'). If you run into previewing problems, please consult -URL `https://orgmode.org/worg/org-tutorials/org-latex-preview.html'." +URL `https://orgmode.org/worg/org-tutorials/org-latex-preview.html'. + +The most comprehensive option can be set with, + + (setq org-latex-src-block-backend \\='engraved) + +which causes source code to be run through +`engrave-faces-latex-buffer', which generates colorings using +Emacs' font-lock information. This requires the Emacs package +engrave-faces (availible from ELPA), and the LaTeX package +fvextra be installed. + +The styling of the engraved result can customised with +`org-latex-engraved-preamble' and `org-latex-engraved-options'. +The default preamble also uses the LaTeX package tcolorbox in +addition to fvextra." :group 'org-export-latex :type '(choice - (const :tag "Use listings" t) + (const :tag "Use listings" listings) (const :tag "Use minted" minted) (const :tag "Use engrave-faces-latex" engraved) - (const :tag "Export verbatim" nil)) - :safe (lambda (s) (memq s '(t nil minted engraved)))) + (const :tag "Export verbatim" verbatim)) + :safe (lambda (s) (memq s '(listings minted engraved verbatim)))) (defcustom org-latex-listings-langs '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp") @@ -1203,7 +1203,7 @@ (defcustom org-latex-engraved-preamble [LISTINGS-SETUP]" "Preamble content injected when using engrave-faces-latex for source blocks. -This is relevant when `org-latex-listings' is set to `engraved'. +This is relevant when `org-latex-src-block-backend' is set to `engraved'. There is quite a lot of flexibility in what this preamble can be, as long as it: @@ -1526,7 +1526,8 @@ (defun org-latex--caption/label-string (element info) main) (and (eq type 'src-block) (not (plist-get attr :float)) - (null (plist-get info :latex-listings))))) + (memq (plist-get info :latex-src-block-backend) + '(verbatim nil))))) (short (org-export-get-caption element t)) (caption-from-attr-latex (plist-get attr :caption))) (cond @@ -1546,7 +1547,8 @@ (defun org-latex--caption/label-string (element info) (paragraph "figure") (image "figure") (special-block "figure") - (src-block (if (plist-get info :latex-listings) + (src-block (if (not (memq (plist-get info :latex-src-block-backend) + '(verbatim nil))) "listing" "figure")) (t (symbol-name type*))) @@ -1933,7 +1935,7 @@ (defun org-latex-template (contents info) (and (stringp template) (format-spec template spec))) ;; engrave-faces-latex preamble - (when (and (eq org-latex-listings 'engraved) + (when (and (eq org-latex-src-block-backend 'engraved) (org-element-map (plist-get info :parse-tree) '(src-block inline-src-block) #'identity info t)) @@ -2321,11 +2323,17 @@ (defun org-latex-inline-src-block (inline-src-block _contents info) contextual information." (let ((code (org-element-property :value inline-src-block)) (lang (org-element-property :language inline-src-block))) - (pcase (plist-get info :latex-listings) - ('nil (org-latex--text-markup code 'code info)) - ('minted (org-latex-inline-src-block--minted info code lang)) - ('engraved (org-latex-inline-src-block--engraved info code lang)) - (_ (org-latex-inline-src-block--listings info code lang))))) + (pcase (plist-get info :latex-src-block-backend) + (`verbatim (org-latex--text-markup code 'code info)) + (`minted (org-latex-inline-src-block--minted info code lang)) + (`engraved (org-latex-inline-src-block--engraved info code lang)) + (`listings (org-latex-inline-src-block--listings info code lang)) + (oldval + (message "Please update the LaTeX src-block-backend to %s" + (if oldval "listings" "verbatim")) + (if oldval + (org-latex-inline-src-block--listings info code lang) + (org-latex--text-markup code 'code info)))))) (defun org-latex-inline-src-block--minted (info code lang) "Transcode an inline src block's content from Org to LaTeX, using minted. @@ -2508,7 +2516,7 @@ (defun org-latex-keyword (keyword _contents info) (concat depth (and depth "\n") "\\tableofcontents")))) ((string-match-p "\\<tables\\>" value) "\\listoftables") ((string-match-p "\\<listings\\>" value) - (cl-case (plist-get info :latex-listings) + (cl-case (plist-get info :latex-src-block-backend) ((nil) "\\listoffigures") (minted "\\listoflistings") (engraved "\\listoflistings") @@ -3195,15 +3203,20 @@ (defun org-latex-src-block (src-block _contents info) (num-start (org-export-get-loc src-block info)) (retain-labels (org-element-property :retain-labels src-block)) (attributes (org-export-read-attribute :attr_latex src-block)) - (float (plist-get attributes :float)) - (listings (plist-get info :latex-listings))) + (float (plist-get attributes :float))) (funcall - (pcase listings - ((or (pred not) (guard (not lang))) #'org-latex-src-block--verbatim) + (pcase (plist-get info :latex-src-block-backend) + ((or `verbatim (guard (not lang))) #'org-latex-src-block--verbatim) + (`minted #'org-latex-src-block--minted) + (`engraved #'org-latex-src-block--engraved) + (`listings #'org-latex-src-block--listings) ((guard custom-env) #'org-latex-src-block--custom) - ('minted #'org-latex-src-block--minted) - ('engraved #'org-latex-src-block--engraved) - (_ #'org-latex-src-block--listings)) + (oldval + (message "Please update the LaTeX src-block-backend to %s" + (if oldval "listings" "verbatim")) + (if oldval + #'org-latex-src-block--listings + #'org-latex-src-block--verbatim))) :src-block src-block :info info :lang lang diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el index 25e02b258..28f950813 100644 --- a/testing/lisp/test-ox.el +++ b/testing/lisp/test-ox.el @@ -3978,7 +3978,7 @@ (ert-deftest test-org-export/latex-src-block-verbatim-caption () \\end{verbatim} \\caption{Caption is below, 60\\%s} \\end{figure*}" - (let ((org-latex-listings 'minted) ; inactive due to missing lang + (let ((org-latex-src-block-backend 'minted) ; inactive due to missing lang (org-latex-default-figure-position "tp")) ;; Namely "multicolumn" value to get just figure environment ;; looks like a bug. -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #9: 0008-ox-latex-Support-setting-the-engraved-theme.patch --] [-- Type: text/x-patch, Size: 3213 bytes --] From 7bc1f26f126449d8e457d88d6344aa1b5d439dfe Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 8 May 2022 02:01:34 +0800 Subject: [PATCH 08/13] ox-latex: Support setting the engraved theme * lisp/ox-latex.el (org-latex-generate-engraved-preamble, org-latex-engraved-theme): Introduce the new export keyword LATEX_ENGRAVED_THEME with default value given by `org-latex-engraved-theme'. This is used to set the engraved theme used in org-latex-engraved-theme. This bumps the minimum required version of engrave-faces from v0.2 to v0.3. --- lisp/ox-latex.el | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index f81625b45..e367e9040 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -129,6 +129,7 @@ (org-export-define-backend 'latex (:latex-diary-timestamp-format nil nil org-latex-diary-timestamp-format) (:latex-engraved-options nil nil org-latex-engraved-options) (:latex-engraved-preamble nil nil org-latex-engraved-preamble) + (:latex-engraved-theme "LATEX_ENGRAVED_THEME" nil org-latex-engraved-theme) (:latex-footnote-defined-format nil nil org-latex-footnote-defined-format) (:latex-footnote-separator nil nil org-latex-footnote-separator) (:latex-format-drawer-function nil nil org-latex-format-drawer-function) @@ -1270,6 +1271,14 @@ (defcustom org-latex-engraved-options :type '(alist :key-type (string :tag "option") :value-type (string :tag "value"))) +(defcustom org-latex-engraved-theme nil + "The theme that should be used for engraved code, when non-nil. +This can be set to any theme defined in `engrave-faces-themes' or +loadable by Emacs. When set to t, the current Emacs theme is +used. When nil, no theme is applied." + :group 'org-export-latex + :type 'symbol) + (defun org-latex-generate-engraved-preamble (info syntax-colours-p) "Generate the preamble to setup engraved code. The result is constructed from the :latex-engraved-preamble and @@ -1278,7 +1287,8 @@ (defun org-latex-generate-engraved-preamble (info syntax-colours-p) `org-latex-engraved-options' respectively." (let* ((engraved-options (plist-get info :latex-engraved-options)) - (engraved-preamble (plist-get info :latex-engraved-preamble))) + (engraved-preamble (plist-get info :latex-engraved-preamble)) + (engraved-theme (plist-get info :latex-engraved-theme))) (when (string-match "^[ \t]*\\[FVEXTRA-SETUP\\][ \t]*\n?" engraved-preamble) (setq engraved-preamble (replace-match @@ -1310,7 +1320,8 @@ (defun org-latex-generate-engraved-preamble (info syntax-colours-p) engraved-preamble "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n" (if (require 'engrave-faces-latex nil t) - (engrave-faces-latex-gen-preamble) + (engrave-faces-latex-gen-preamble + (when engraved-theme (intern engraved-theme))) (message "Cannot engrave source blocks. Consider installing `engrave-faces'.") "% WARNING syntax highlighting unavailible as engrave-faces-latex was missing.\n") "\n") -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #10: 0009-ox-latex-Support-setting-engraved-theme-per-block.patch --] [-- Type: text/x-patch, Size: 9236 bytes --] From 24db3cc69c2e28e4207532ac5181e27a28456eae Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Sun, 8 May 2022 15:28:29 +0800 Subject: [PATCH 09/13] ox-latex: Support setting engraved theme per-block * lisp/ox-latex.el (org-latex-src-block--engraved, org-latex-src--engrave-code, org-latex-inline-src-block--engraved, org-latex-generate-engraved-preamble): Allow for the engraved theme used to be set on a per-src-block basis with #+attr_latex: :engraved-theme THEME. Extra setup code is now generated in `org-latex-generate-engraved-preamble'. To facilitate the application of themes to src blocks, `org-latex-src--engrave-code' now takes on a larger portion of the transcoding work. --- lisp/ox-latex.el | 120 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 96 insertions(+), 24 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index e367e9040..9634461bd 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -1288,7 +1288,27 @@ (defun org-latex-generate-engraved-preamble (info syntax-colours-p) (let* ((engraved-options (plist-get info :latex-engraved-options)) (engraved-preamble (plist-get info :latex-engraved-preamble)) - (engraved-theme (plist-get info :latex-engraved-theme))) + (engraved-theme (plist-get info :latex-engraved-theme)) + (engraved-themes + (cl-delete-duplicates + (org-element-map + (plist-get info :parse-tree) + '(src-block inline-src-block) + (lambda (src) + (plist-get + (org-export-read-attribute :attr_latex src) + :engraved-theme)) + info))) + (gen-theme-spec + (lambda (theme) + (if (eq engrave-faces-latex-output-style 'preset) + (engrave-faces-latex-gen-preamble (when theme (intern theme))) + (engrave-faces-latex-gen-preamble-line + 'default + (alist-get 'default + (if theme + (engrave-faces-get-theme (intern theme)) + engrave-faces-current-preset-style))))))) (when (string-match "^[ \t]*\\[FVEXTRA-SETUP\\][ \t]*\n?" engraved-preamble) (setq engraved-preamble (replace-match @@ -1318,10 +1338,31 @@ (defun org-latex-generate-engraved-preamble (info syntax-colours-p) (concat "\n% Setup for code blocks [1/2]\n\n" engraved-preamble - "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n" + "\n\n% Setup for code blocks [2/2]: syntax highlighting colors\n\n" (if (require 'engrave-faces-latex nil t) - (engrave-faces-latex-gen-preamble - (when engraved-theme (intern engraved-theme))) + (if engraved-themes + (concat + (mapconcat + (lambda (theme) + (format + "\n\\newcommand{\\engravedtheme%s}{%%\n%s\n}" + (replace-regexp-in-string "[^A-Za-z]" "" theme) + (replace-regexp-in-string + "newcommand" "renewcommand" + (replace-regexp-in-string + "#" "##" + (funcall gen-theme-spec theme))))) + engraved-themes + "\n") + "\n\n" + (cond + ((memq engraved-theme engraved-themes) + (concat "\\engravedtheme" + (replace-regexp-in-string + "[^A-Za-z]" "" engraved-theme) + "\n")) + (t (funcall gen-theme-spec engraved-theme)))) + (funcall gen-theme-spec engraved-theme)) (message "Cannot engrave source blocks. Consider installing `engrave-faces'.") "% WARNING syntax highlighting unavailible as engrave-faces-latex was missing.\n") "\n") @@ -2359,10 +2400,11 @@ (defun org-latex-inline-src-block--minted (info code lang) mint-lang code))) -(defun org-latex-inline-src-block--engraved (_info code lang) +(defun org-latex-inline-src-block--engraved (info code lang) "Transcode an inline src block's content from Org to LaTeX, using engrave-faces. INFO, CODE, and LANG are provided by `org-latex-inline-src-block'." - (format "\\Verb{%s}" (org-latex-src--engrave-code code lang))) + (org-latex-src--engrave-code + code lang nil (plist-get info :latex-engraved-options) t)) (defun org-latex-inline-src-block--listings (info code lang) "Transcode an inline src block's content from Org to LaTeX, using lstlistings. @@ -3347,13 +3389,25 @@ (cl-defun org-latex-src-block--minted ;; Return value. (format float-env body))) -(defun org-latex-src--engrave-code (content lang) - "Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result." +(defun org-latex-src--engrave-code (content lang &optional theme options inline) + "Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result. +When the THEME symbol is non-nil, that theme will be used. + +When INLINE is nil, a Verbatim environment wrapped in a Code +environment will be used. When t, a Verb command will be used. + +When OPTIONS is provided, as either a string or list of key-value +pairs accepted by `org-latex--make-option-string', it is passed +to the Verbatim environment or Verb command." (if (require 'engrave-faces-latex nil t) (let* ((lang-mode (and lang (org-src-get-lang-mode lang))) + (engrave-faces-current-preset-style + (if theme + (engrave-faces-get-theme theme) + engrave-faces-current-preset-style)) (engraved-buffer (with-temp-buffer - (insert content) + (insert (string-trim-right content "\n")) (when lang-mode (if (functionp lang-mode) (funcall lang-mode) @@ -3362,9 +3416,27 @@ (defun org-latex-src--engrave-code (content lang) (engrave-faces-latex-buffer))) (engraved-code (with-current-buffer engraved-buffer - (buffer-string)))) + (buffer-string))) + (engraved-options + (when options + (concat "[" + (if (listp options) + (org-latex--make-option-string options) + options) + "]"))) + (engraved-wrapped + (if inline + (concat "\\Verb" engraved-options "{" engraved-code "}") + (concat "\\begin{Code}\n\\begin{Verbatim}" engraved-options "\n" + engraved-code "\n\\end{Verbatim}\n\\end{Code}")))) (kill-buffer engraved-buffer) - engraved-code) + (if theme + (concat "{\\engravedtheme" + (replace-regexp-in-string "[^A-Za-z]" "" + (symbol-name theme)) + engraved-wrapped + "}") + engraved-wrapped)) (user-error "Cannot engrave code as `engrave-faces-latex' is unavailible."))) (cl-defun org-latex-src-block--engraved @@ -3392,7 +3464,15 @@ (cl-defun org-latex-src-block--engraved placement) "%s\n\\end{listing}")) (t "%s"))) - (options (plist-get info :latex-engraved-options)) + (options + (let ((engraved-options (plist-get info :latex-engraved-options)) + (local-options (plist-get attributes :options))) + (append + (when (and num-start (not (assoc "linenos" engraved-options))) + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start))))) + (and local-options (list local-options))))) + (engraved-theme (plist-get attributes :engraved-theme)) (content (let* ((code-info (org-export-unravel-code src-block)) (max-width @@ -3414,18 +3494,10 @@ (cl-defun org-latex-src-block--engraved (format "(%s)" ref))))) nil (and retain-labels (cdr code-info))))) (body - (format - "\\begin{Code}\n\\begin{Verbatim}[%s]\n%s\\end{Verbatim}\n\\end{Code}" - ;; Options. - (concat - (org-latex--make-option-string - (append - (when (and num-start (not (assoc "linenos" options))) - `(("linenos") - ("firstnumber" ,(number-to-string (1+ num-start))))) - (let ((local-options (plist-get attributes :options))) - (and local-options (list local-options)))))) - (org-latex-src--engrave-code content lang)))) + (org-latex-src--engrave-code + content lang + (when engraved-theme (intern engraved-theme)) + options))) (format float-env body))) (cl-defun org-latex-src-block--listings -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #11: 0010-ox-latex-Fix-captions-in-minted-engraved-code.patch --] [-- Type: text/x-patch, Size: 4986 bytes --] From 7d9306fe8ada094ff6964422cc527645eb9ffc55 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Mon, 9 May 2022 00:04:10 +0800 Subject: [PATCH 10/13] ox-latex: Fix %-captions in minted/engraved code * lisp/ox-latex.el (org-latex-src-block--engraved, org-latex-src-block--minted): Refactor float-env to be clearer, and switch from `format' to `concat' to fix the bug where %-chars in captions are interpreted as a format specifier. --- lisp/ox-latex.el | 55 +++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 9634461bd..ceb1bd483 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -3330,23 +3330,20 @@ (cl-defun org-latex-src-block--minted (let* ((caption-str (org-latex--caption/label-string src-block info)) (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) (plist-get info :latex-default-figure-position))) + (multicolumn-p (string= "multicolumn" float)) (float-env (cond - ((string= "multicolumn" float) - (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - (caption - (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) + ((or caption multicolumn-p) + (cons + (concat "\\begin{listing" (when multicolumn-p "*") + "}[" placement "]\n" + (if caption-above-p caption-str "")) + (concat "\n" (if caption-above-p "" caption-str) + "\\end{listing" (when multicolumn-p "*") "}"))) ((string= "t" float) - (concat (format "\\begin{listing}[%s]\n" - placement) - "%s\n\\end{listing}")) - (t "%s"))) + (cons + (concat "\\begin{listing}[" placement "]\n") + "\n\\end{listing}")))) (options (plist-get info :latex-minted-options)) (body (format @@ -3386,8 +3383,7 @@ (cl-defun org-latex-src-block--minted ?\s) (format "(%s)" ref))))) nil (and retain-labels (cdr code-info))))))) - ;; Return value. - (format float-env body))) + (concat (car float-env) body (cdr float-env)))) (defun org-latex-src--engrave-code (content lang &optional theme options inline) "Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result. @@ -3447,23 +3443,20 @@ (cl-defun org-latex-src-block--engraved (let* ((caption-str (org-latex--caption/label-string src-block info)) (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) (plist-get info :latex-default-figure-position))) + (multicolumn-p (string= "multicolumn" float)) (float-env (cond - ((string= "multicolumn" float) - (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) - (caption - (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" - placement - (if caption-above-p caption-str "") - (if caption-above-p "" caption-str))) + ((or caption multicolumn-p) + (cons + (concat "\\begin{listing" (when multicolumn-p "*") + "}[" placement "]\n" + (if caption-above-p caption-str "")) + (concat "\n" (if caption-above-p "" caption-str) + "\\end{listing" (when multicolumn-p "*") "}"))) ((string= "t" float) - (concat (format "\\begin{listing}[%s]\n" - placement) - "%s\n\\end{listing}")) - (t "%s"))) + (cons + (concat "\\begin{listing}[" placement "]\n") + "\n\\end{listing}")))) (options (let ((engraved-options (plist-get info :latex-engraved-options)) (local-options (plist-get attributes :options))) @@ -3498,7 +3491,7 @@ (cl-defun org-latex-src-block--engraved content lang (when engraved-theme (intern engraved-theme)) options))) - (format float-env body))) + (concat (car float-env) body (cdr float-env)))) (cl-defun org-latex-src-block--listings (&key src-block info lang caption caption-above-p label num-start retain-labels attributes float &allow-other-keys) -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #12: 0011-ox-latex-Support-mathescape-d-code-with-engraved.patch --] [-- Type: text/x-patch, Size: 3891 bytes --] From 5fdbbbe811a4d15fa1f7fa4bfad9d3e11e6f4eb8 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 11 May 2022 23:18:19 +0800 Subject: [PATCH 11/13] ox-latex: Support mathescape'd code with engraved * lisp/ox-latex.el (org-latex-src-block--engraved, org-latex-src--engrave-mathescape-p): Using the mathescape functionality in engrave-faces-latex v0.3.1, we can support the mathescape option of fvextra well. Along the way, we fix a minor issue with the localoptions list in `org-latex-src-block--engraved`. --- lisp/ox-latex.el | 46 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index ceb1bd483..29543f8e9 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -3385,6 +3385,40 @@ (cl-defun org-latex-src-block--minted nil (and retain-labels (cdr code-info))))))) (concat (car float-env) body (cdr float-env)))) +(defun org-latex-src--engrave-mathescape-p (info options) + "From the export INFO plist, and the per-block OPTIONS, determine mathescape." + (let ((default-options (plist-get info :latex-engraved-options)) + (mathescape-status + (lambda (opts) + (cl-some + (lambda (opt) + (or (and + (null (cdr opt)) + (cond + ((string-match-p + "\\(?:^\\|,\\)mathescape=false\\(?:,\\|$\\)" + (car opt)) + 'no) + ((or (string-match-p + "\\(?:^\\|,\\)mathescape\\(?:=true\\)?\\(?:,\\|$\\)" + (car opt)) + (string= "mathescape" (car opt))) + 'yes))) + (and + (string= (car opt) "mathescape") + (cond + ((or (and (stringp (cdr opt)) (string= (cdr opt) "true")) + (equal '("true") (cdr opt))) + 'yes) + ((or (and (stringp (cdr opt)) (string= "false" (cdr opt))) + (equal '("false") (cdr opt))) + 'no))))) + opts)))) + (if-let ((mathescape (or (funcall mathescape-status default-options) + (funcall mathescape-status options)))) + (when (eq mathescape 'yes) + (or engrave-faces-latex-mathescape t))))) + (defun org-latex-src--engrave-code (content lang &optional theme options inline) "Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result. When the THEME symbol is non-nil, that theme will be used. @@ -3464,7 +3498,7 @@ (cl-defun org-latex-src-block--engraved (when (and num-start (not (assoc "linenos" engraved-options))) `(("linenos") ("firstnumber" ,(number-to-string (1+ num-start))))) - (and local-options (list local-options))))) + (and local-options `((,local-options)))))) (engraved-theme (plist-get attributes :engraved-theme)) (content (let* ((code-info (org-export-unravel-code src-block)) @@ -3487,10 +3521,12 @@ (cl-defun org-latex-src-block--engraved (format "(%s)" ref))))) nil (and retain-labels (cdr code-info))))) (body - (org-latex-src--engrave-code - content lang - (when engraved-theme (intern engraved-theme)) - options))) + (let ((engrave-faces-latex-mathescape + (org-latex-src--engrave-mathescape-p info options))) + (org-latex-src--engrave-code + content lang + (when engraved-theme (intern engraved-theme)) + options)))) (concat (car float-env) body (cdr float-env)))) (cl-defun org-latex-src-block--listings -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #13: 0012-news-and-manual-Mention-ox-latex-s-engraved-code.patch --] [-- Type: text/x-patch, Size: 4727 bytes --] From a57baf2c0f863aba49264875fd93d62a602ec0d9 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Thu, 12 May 2022 00:03:11 +0800 Subject: [PATCH 12/13] news and manual: Mention ox-latex's engraved code * etc/ORG-NEWS: Mention the addition of the "engraved" source block transcoding backend. * doc/org-manual.org (Footnotes, LaTeX specific properties, Source blocks in LaTeX export): Basic documentation on the "engraved" source block transcoding backend. --- doc/org-manual.org | 25 ++++++++++++++++--------- etc/ORG-NEWS | 9 +++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index 60bded419..7cba5f18d 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -13811,22 +13811,26 @@ *** Source blocks in LaTeX export #+vindex: org-latex-listings-options #+vindex: org-latex-minted-options +#+vindex: org-latex-engraved-options The LaTeX export back-end passes string values in =:options= to LaTeX packages for customization of that specific source block. In the -example below, the =:options= are set for Minted. Minted is a source -code highlighting LaTeX package with many configurable options[fn:134]. +example below, the =:options= are set for Engraved or Minted. Minted +is a source code highlighting LaTeX package with many configurable +options[fn:134]. Both Minted and Engraved are built on [[https://www.ctan.org/pkg/fvextra][fvextra]], and +so support many of the same options. #+begin_example -,#+ATTR_LATEX: :options commentstyle=\bfseries +,#+ATTR_LATEX: :options mathescape ,#+BEGIN_SRC emacs-lisp - (defun Fib (n) + (defun Fib (n) ; $n_i = n_{i-2} + n_{i-1}$ (if (< n 2) n (+ (Fib (- n 1)) (Fib (- n 2))))) ,#+END_SRC #+end_example -To apply similar configuration options for all source blocks in -a file, use the ~org-latex-listings-options~ and -~org-latex-minted-options~ variables. +To apply similar configuration options for all source blocks in a +file, use the ~org-latex-listings-options~, +~org-latex-engraved-options~, and ~org-latex-minted-options~ +variables. *** Example blocks in LaTeX export :PROPERTIES: @@ -16289,6 +16293,9 @@ **** LaTeX specific properties | ~:latex-default-table-environment~ | ~org-latex-default-table-environment~ | | ~:latex-default-table-mode~ | ~org-latex-default-table-mode~ | | ~:latex-diary-timestamp-format~ | ~org-latex-diary-timestamp-format~ | +| ~:latex-engraved-options~ | ~org-latex-engraved-options~ | +| ~:latex-engraved-preamble~ | ~org-latex-engraved-preamble~ | +| ~:latex-engraved-theme~ | ~org-latex-engraved-theme~ | | ~:latex-footnote-defined-format~ | ~org-latex-footnote-defined-format~ | | ~:latex-footnote-separator~ | ~org-latex-footnote-separator~ | | ~:latex-format-drawer-function~ | ~org-latex-format-drawer-function~ | @@ -22255,8 +22262,8 @@ * Footnotes [fn:114] This works automatically for the HTML backend (it requires version 1.34 of the =htmlize.el= package, which you need to install). Fontified code chunks in LaTeX can be achieved using either the -[[https://www.ctan.org/pkg/listings][listings]] package or the [[https://www.ctan.org/pkg/minted][minted]] package. Refer to -~org-latex-src-block-backend~ for details. +[[https://www.ctan.org/pkg/listings][listings]] LaTeX package, [[https://www.ctan.org/pkg/minted][minted]] LaTeX package, or by using +[[https://elpa.gnu.org/packages/engrave-faces.html][engrave-faces]] . Refer to ~org-latex-src-block-backend~ for details. [fn:115] Source code in code blocks may also be evaluated either interactively or on export. See [[*Working with Source Code]] for more diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index ebb3cd649..582816534 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -180,6 +180,15 @@ commands. =:noweb-prefix= can be set to =no= to prevent the prefix characters from being repeated when expanding a multiline noweb reference. +*** New LaTeX source block backend using =engraved-faces-latex= + +When ~org-latex-src-block-backend~ is set to ~engraved~, +=engrave-faces-latex= from [[http://elpa.gnu.org/packages/engrave-faces.html][engrave-faces]] is used to transcode source +blocks to LaTeX. This requires the =fvextra=, =float=, and (by +default, but not necessarily) =tcolorbox= LaTeX packages be +installed. It uses Emacs' font-lock information, and so tends to +produce results superior to Minted or Listings. + ** New functions and changes in function arguments *** New function ~org-element-cache-map~ for quick mapping across Org elements -- 2.35.3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #14: 0013-ox-latex-Prefix-lst-to-source-block-labels.patch --] [-- Type: text/x-patch, Size: 848 bytes --] From c3851e657611424af10859a2236c0b4e183cc1d7 Mon Sep 17 00:00:00 2001 From: TEC <tec@tecosaur.com> Date: Wed, 11 May 2022 21:50:36 +0800 Subject: [PATCH 13/13] ox-latex: Prefix lst: to source block labels * lisp/ox-latex.el (org-latex--label): Use the "lst:" prefix when generating source block labels ("lst" contracted from "listing"). --- lisp/ox-latex.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 29543f8e9..998f2238d 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -1554,6 +1554,7 @@ (defun org-latex--label (datum info &optional force full) (`paragraph (and (org-element-property :caption datum) "fig:")) + (`src-block "lst:") (_ nil)) (org-export-get-reference datum info)))))) (cond ((not full) label) -- 2.35.3 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH] (v3) New LaTeX code export option: engraved 2022-05-11 16:05 ` [PATCH] (v3) " Timothy @ 2022-05-12 16:40 ` Daniel Fleischer 2022-05-12 16:44 ` Timothy 0 siblings, 1 reply; 27+ messages in thread From: Daniel Fleischer @ 2022-05-12 16:40 UTC (permalink / raw) To: Timothy; +Cc: Ihor Radchenko, emacs-orgmode, Nicolas Goaziou Looks good. I had to update `engrave-faces' to 0.3 because of new variables/functions and it works now. It does what it says on the box so let's move forward introducing these changes and be open to feedback. Thank you very much for introducing this feature! -- Daniel Fleischer ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] (v3) New LaTeX code export option: engraved 2022-05-12 16:40 ` Daniel Fleischer @ 2022-05-12 16:44 ` Timothy 0 siblings, 0 replies; 27+ messages in thread From: Timothy @ 2022-05-12 16:44 UTC (permalink / raw) To: Daniel Fleischer; +Cc: Ihor Radchenko, emacs-orgmode, Nicolas Goaziou [-- Attachment #1: Type: text/plain, Size: 635 bytes --] Hi Daniel, > Looks good. I had to update `engrave-faces’ to 0.3 because of new > variables/functions and it works now. It does what it says on the box so > let’s move forward introducing these changes and be open to feedback. > > Thank you very much for introducing this feature! That’s great to hear! I’ve just tagged and pushed 0.3.1 of engrave-faces, so HEAD is no longer required, along with my patch of ox-latex commits. Thanks for helping with the process of getting this in, this has been over a year in the works and so it feels fantastic to have this feature in-tree at last! All the best, Timothy ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-05 15:17 ` Timothy 2022-05-05 16:13 ` Timothy @ 2022-05-05 16:48 ` Max Nikulin 2022-05-07 4:13 ` Ihor Radchenko 1 sibling, 1 reply; 27+ messages in thread From: Max Nikulin @ 2022-05-05 16:48 UTC (permalink / raw) To: emacs-orgmode On 05/05/2022 22:17, Timothy wrote: > Subject: [PATCH 1/4] ox-latex: Refactor `org-latex-src-block' When I was trying to fix an issue with caption, I was not brave enough for massive changes. I do not like the original code of the function. There are some unit tests for exporting of src blocks. Maybe the new option should be tested as well. > +(defun org-latex-src-block--verbatim > + (src-block info _lang caption caption-above-p _label > + _num-start _retain-labels _attributes float) On the one hand I have no a better suggestion, but on the other hand 10 arguments is too much for straightforward code from my point of view. Unsure that getting parameters in each function or passing a property list would not be worse however. It reminds me a case when a colleague failed in despair trying to figure out what was wrong with his 15 argument fortran function. I do not remember exactly whether it was a missed argument or an extra one. The last one was assumed to be a parameter (constant) and the identifier was not available in debugger since compiler just substituted the number without creation of a symbol and it added even more confusion. My other notes are rather loosely related to your patches. The issues may be postponed till someone will start a new thread for them. My hope is that some of them might be easily addressed so that they will not need separate testing. A problem with percent sign in captions is tracked on updates.orgmode.org. Some environments has not fixed yet: https://list.orgmode.org/YT2PR01MB45101E27DC6251D8F8B7B366F6EC9@YT2PR01MB4510.CANPRD01.PROD.OUTLOOK.COM/ That time I was puzzled why the option is named "multicolumn" while only regular "figure" is added: > + (cond ((string= "multicolumn" float) > + (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" If language is added to "#+begin_example:" than the block content is properly fontified in the Emacs buffer. It would be great to treat such example similar to source block during export. When some code is not supposed to be executed, it is natural to use example block. I am curious if new functions may be reused. ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-05 16:48 ` [PATCH] " Max Nikulin @ 2022-05-07 4:13 ` Ihor Radchenko 0 siblings, 0 replies; 27+ messages in thread From: Ihor Radchenko @ 2022-05-07 4:13 UTC (permalink / raw) To: Max Nikulin; +Cc: emacs-orgmode Max Nikulin <manikulin@gmail.com> writes: >> +(defun org-latex-src-block--verbatim >> + (src-block info _lang caption caption-above-p _label >> + _num-start _retain-labels _attributes float) > > On the one hand I have no a better suggestion, but on the other hand 10 > arguments is too much for straightforward code from my point of view. > Unsure that getting parameters in each function or passing a property > list would not be worse however. I agree that having that many unused arguments is awkward, especially when the arguments are repeated in all the calls. Maybe the functions could be rewritten using cl-defun with keys and &allow-other-keys and then called via apply on a let-bound arg plist? Best, Ihor ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-04 15:59 [PATCH] New LaTeX code export option: engraved Timothy ` (2 preceding siblings ...) 2022-05-05 8:48 ` Ihor Radchenko @ 2022-05-09 19:19 ` Sébastien Miquel 2022-05-10 1:13 ` Timothy 3 siblings, 1 reply; 27+ messages in thread From: Sébastien Miquel @ 2022-05-09 19:19 UTC (permalink / raw) To: Timothy, emacs-orgmode Hi Timothy, I'm quite exited and impressed to see this alternative to minted, thank you. I haven't been able to test your patches to org, but I have tried engrave-faces.el. Here's a couple issues I've run into. 1. engrave-faces-generate-preset generates emacs colors such as `:foreground "grey70"` which are not supported by engrave-faces-latex-gen-preamble-line and co. 2. `minted` supports a `mathescape` option to render math content inside code. `fvextra` supports the same option, but maths characters are escaped by engrave-faces-latex-face-mapper. Regards, -- Sébastien Miquel ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-09 19:19 ` Sébastien Miquel @ 2022-05-10 1:13 ` Timothy 2022-05-10 16:10 ` Timothy 0 siblings, 1 reply; 27+ messages in thread From: Timothy @ 2022-05-10 1:13 UTC (permalink / raw) To: sebastien.miquel; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 1087 bytes --] Hi Sebastien, > I’m quite exited and impressed to see this alternative to minted, > thank you. That’s great to hear! > I haven’t been able to test your patches to org, but I have tried > engrave-faces.el. Here’s a couple issues I’ve run into. Still helpful, thanks. > 1. engrave-faces-generate-preset generates emacs colors such as > `:foreground “grey70”` which are not supported by > engrave-faces-latex-gen-preamble-line and co. Ah. I’ve just found this snippet from `list-colors-print' ┌──── │ (apply 'format "#%02x%02x%02x" │ (mapcar (lambda (c) (ash c -8)) │ (color-values (car color)))) └──── I’ll see if I can incorporate this into engrave-faces v0.3.1. > 2. `minted` supports a `mathescape` option to render math content > inside code. `fvextra` supports the same option, but maths > characters are escaped by engrave-faces-latex-face-mapper. I’l also take a look at this :) Thanks for the comments Sebastien. All the best, Timothy ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-10 1:13 ` Timothy @ 2022-05-10 16:10 ` Timothy 2022-05-10 17:53 ` Sébastien Miquel 0 siblings, 1 reply; 27+ messages in thread From: Timothy @ 2022-05-10 16:10 UTC (permalink / raw) To: sebastien.miquel; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 757 bytes --] Hi Sebastien, >> 1. engrave-faces-generate-preset generates emacs colors such as >> `:foreground “grey70”` which are not supported by >> engrave-faces-latex-gen-preamble-line and co. > > I’ll see if I can incorporate this into engrave-faces v0.3.1. Done. >> 2. `minted` supports a `mathescape` option to render math content >> inside code. `fvextra` supports the same option, but maths >> characters are escaped by engrave-faces-latex-face-mapper. > > I’l also take a look at this :) Implemented in engrave-faces-latex, but not worked into ox-html yet. If you could check it out on the engrave-faces-latex side and check it’s behaving sanely, that would be helpful. All the best, Timothy ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH] New LaTeX code export option: engraved 2022-05-10 16:10 ` Timothy @ 2022-05-10 17:53 ` Sébastien Miquel 0 siblings, 0 replies; 27+ messages in thread From: Sébastien Miquel @ 2022-05-10 17:53 UTC (permalink / raw) To: Timothy; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 532 bytes --] Hi, Timothy writes: >>> 2. `minted` supports a `mathescape` option to render math content >>> inside code. `fvextra` supports the same option, but maths >>> characters are escaped by engrave-faces-latex-face-mapper. >> I’l also take a look at this:) > Implemented in engrave-faces-latex, but not worked into ox-html yet. If you > could check it out on the engrave-faces-latex side and check it’s behaving > sanely, that would be helpful. I've tried it, and mathescape works, thanks ! -- Sébastien Miquel [-- Attachment #2: Type: text/html, Size: 1411 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2022-05-12 16:49 UTC | newest] Thread overview: 27+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2022-05-04 15:59 [PATCH] New LaTeX code export option: engraved Timothy 2022-05-05 7:52 ` Daniel Fleischer 2022-05-05 16:09 ` Timothy 2022-05-06 2:35 ` Ihor Radchenko 2022-05-06 11:23 ` Timothy 2022-05-05 7:54 ` Daniel Fleischer 2022-05-05 8:48 ` Ihor Radchenko 2022-05-05 15:17 ` Timothy 2022-05-05 16:13 ` Timothy 2022-05-07 5:16 ` Ihor Radchenko 2022-05-07 6:57 ` Timothy 2022-05-07 10:40 ` Timothy 2022-05-07 11:33 ` Daniel Fleischer 2022-05-08 14:30 ` [PATCH] (v2) " Timothy 2022-05-09 6:20 ` Ihor Radchenko 2022-05-09 12:57 ` Timothy 2022-05-10 8:00 ` Max Nikulin 2022-05-11 11:06 ` Ihor Radchenko 2022-05-11 16:05 ` [PATCH] (v3) " Timothy 2022-05-12 16:40 ` Daniel Fleischer 2022-05-12 16:44 ` Timothy 2022-05-05 16:48 ` [PATCH] " Max Nikulin 2022-05-07 4:13 ` Ihor Radchenko 2022-05-09 19:19 ` Sébastien Miquel 2022-05-10 1:13 ` Timothy 2022-05-10 16:10 ` Timothy 2022-05-10 17:53 ` Sébastien Miquel
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.