diff --git a/README.org b/README.org index 6131e3d..ff8189f 100644 --- a/README.org +++ b/README.org @@ -2322,109 +2322,40 @@ valid directories and files. In an [[https://orgmode.org/][Org-mode]] buffer th This package aims to produce a versatile generic core which can process a fontified buffer and pass the data to any number of backends to deal with -specific output formats and it should work with =org-mode=. *Thanks to the -listings below*, [[https://github.com/tecosaur/engrave-faces#readme][Engrave Faces]] and [[info:org#Source blocks in LaTeX export][Org source block export to LaTeX (info)]] *are -capable of handling this [[file:README.org]] file:* -1. Listing [[lst:ensure-engrave-faces-with-latex-face-mapper-fix]] ensures - installation of =engrave-faces= and makes =engrave-faces-latex-face-mapper= - handle multi-line documentation strings. -2. Listing [[lst:ensure-engrave-faces-with-latex-face-apply-fix]] ensures - installation of =engrave-faces= and makes =engrave-faces-latex-face-apply= - handle symbolic color name strings (in addition to the hexadecimal strings). -3. The =org-latex-engraved-source-block-filter= in listing +specific output formats and Org offers it as an alternative to =minted=. *The +listings below make* [[https://github.com/tecosaur/engrave-faces#readme][Engrave Faces]] and [[info:org#Source blocks in LaTeX export][Org source block export to LaTeX (info)]] +*capable of handling this [[file:README.org]] file to my satisfaction:* +1. The default Org export configuration for engraving listings produces =pdf= + output with a non-equidistant interline spacing in floating listings and + equidistant interline spaces non-floating =tcolorbox= environments. I have + traced non-equidistance interline spacing back to the =breakable= option in + =Code= environments inside =listing= environments. However, =tcolorbox= + requires =breakable= for listings that do not fit on a page. As a + work-around, the filter =org-latex-engraved-source-block-filter= in listing [[lst:org-latex-engraved-source-block-filter]] and the =org-latex-engraved-preamble= customization in listing [[lst:smart-latex-engrave-org-source-blocks]] allow to engrave =org-mode= source - blocks to "floating unbreakable" or "non-floating breakable" LaTeX - environments. + blocks to "floating unbreakable with a caption" or "non-floating breakable + without a caption" LaTeX environments. +2. Listing [[lst:ensure-engrave-faces-with-latex-face-apply-fix]] makes + =engrave-faces-latex-face-apply= handle symbolic color name strings (in + addition to the hexadecimal strings). Since for instance the faces in + src_emacs-lisp{(find-library "org-faces")} have symbolic color names, this + fix allows to engrave org-mode source blocks during LaTeX export without any + further tweaking. +3. Listing [[lst:ensure-engrave-faces-with-latex-face-mapper-fix]] makes + =engrave-faces-latex-face-mapper= handle horizontal and vertical whitespace + in multiple line documentation strings correctly. For instance, *without this + fix* the empty line in the documentation string of + =org-latex-engraved-sourc-block-filter= of listing + [[lst:org-latex-engraved-source-block-filter]] is invisible in the exported =pdf= + file and *very obviously* the mishandling of the spacing destroys the + indentation in Python documentation strings. The idea of the fix is to let + the LaTeX face mapper wrap only groups of "words joined by blank characters" + in LaTeX commands and pass "newlines and other whitespace between those + groups" on without wrapping. 4. Listing [[lst:ox-engraved-emacs-lisp-setup]] shows how to use this configuration. -#+caption[Ensure =engrave-faces= installation and fix multiline docstrings]: -#+caption: Ensure =engrave-faces= installation and fix multiline docstrings. -#+name: lst:ensure-engrave-faces-with-latex-face-mapper-fix -#+begin_src emacs-lisp - (when (and (ensure-package-installation 'engrave-faces) - (require 'engrave-faces-latex nil t)) - (defun engrave-faces-latex-face-mapper-override (faces content) - "Create a LaTeX representation of CONTENT With FACES applied." - (let* ((style (engrave-faces-preset-style faces)) - (protected-content - (funcall - (if (and engrave-faces-latex-mathescape - (eq 'font-lock-comment-face (car style))) - #'engrave-faces-latex--protect-content-mathescape - #'engrave-faces-latex--protect-content) - content))) - ;; Wrap groups of "words joined by blank characters" in LaTeX commands. - ;; Do not wrap newlines and other whitespace between those groups. - (let ((regexp (rx (or (group-n 1 (+ graph ) (* (+ blank) (+ graph))) - (group-n 2 (+ (any "\n" space)))))) - (slug (when (and style - (eq engrave-faces-latex-output-style 'preset)) - (plist-get (cdr style) :slug))) - (start 0) - (stack)) - (while (string-match regexp protected-content start) - (setq start (match-end 0)) - (when-let ((pc (match-string 1 protected-content))) - (if (stringp slug) - (push (concat "\\EF" slug "{" pc "}") stack) - (push (engrave-faces-latex-face-apply faces pc) stack))) - (when-let ((pc (match-string 2 protected-content))) - (push pc stack))) - (apply #'concat (nreverse stack)))))) - - (with-eval-after-load 'emacs - (defun toggle-engrave-faces-latex-face-mapper-override () - "Toggle `engrave-faces-latex-face-mapper' advice." - (interactive) - (toggle-advice 'engrave-faces-latex-face-mapper - :override #'engrave-faces-latex-face-mapper-override)) - - (toggle-engrave-faces-latex-face-mapper-override)) -#+end_src - -#+caption[Ensure =engrave-faces= installation and fix symbolic colors]: -#+caption: Ensure =engrave-faces= installation and fix symbolic colors. -#+name: lst:ensure-engrave-faces-with-latex-face-apply-fix -#+begin_src emacs-lisp - (when (and (ensure-package-installation 'engrave-faces) - (require 'engrave-faces-latex nil t)) - (defun engrave-faces-latex--color (color) - "Convert COLOR loosely to a string of six hexadecimal digits." - (if (char-equal ?# (aref color 0)) - (substring color 1 7) - (apply 'format "%02x%02x%02x" - (mapcar (lambda (c) (ash c -8)) - (color-values color))))) - - (defun engrave-faces-latex-face-apply-override (faces content) - "Convert attributes of FACES to LaTeX commands applied to CONTENT." - (let ((attrs (engrave-faces-merge-attributes faces))) - (let ((bg (plist-get attrs :background)) - (fg (plist-get attrs :foreground)) - (it (eql (plist-get attrs :slant) 'italic)) - (bl (member (plist-get attrs :weight) '(bold extra-bold))) - (st (plist-get attrs :strike-through))) - (concat - (when bg (concat "\\colorbox[HTML]{" - (engrave-faces-latex--color bg) "}{")) - (when fg (concat "\\textcolor[HTML]{" - (engrave-faces-latex--color fg) "}{")) - (when st "\\sout{") (when bl "\\textbf{") (when it "\\textit{") - content - (when bg "}") (when fg "}") (when st "}") (when bl "}") (when it "}")))))) - - (with-eval-after-load 'emacs - (defun toggle-engrave-faces-latex-face-apply-override () - "Toggle `engrave-faces-latex-face-apply' advice." - (interactive) - (toggle-advice 'engrave-faces-latex-face-apply - :override #'engrave-faces-latex-face-apply-override)) - - (toggle-engrave-faces-latex-face-apply-override)) -#+end_src - #+caption[Engrave to floating unbreakable or non-floating breakable environments]: #+caption: Define an =org-export= filter function to engrave =org-src-mode= #+caption: blocks to floating unbreakable LaTeX environments or non-floating @@ -2443,6 +2374,7 @@ capable of handling this [[file:README.org]] file:* (let ((enter "^\\\\begin{Code}\n\\\\begin{Verbatim}") (leave "^\\\\end{Verbatim}\n\\\\end{Code}")) ;; Transform only blocks matching the enter regexp at position 0. + ;; Do not transform blocks that are listing environments. (when (and (string-match enter data) (eql 0 (match-beginning 0))) (setq data (replace-match "\\begin{Breakable}\n\\begin{Verbatim}" t t data)) @@ -2456,8 +2388,8 @@ capable of handling this [[file:README.org]] file:* data))))) #+end_src -#+caption[Enable smart LaTeX engraving of =org-src-mode= blocks]: -#+caption: Enable smart LaTeX engraving of =org-src-mode= blocks. +#+caption[Smart LaTeX engraving of =org-src-mode= blocks]: +#+caption: Smart LaTeX engraving of =org-src-mode= blocks. #+name: lst:smart-latex-engrave-org-source-blocks #+begin_src emacs-lisp (defun smart-latex-engrave-org-source-blocks () @@ -2506,6 +2438,102 @@ capable of handling this [[file:README.org]] file:* [LISTINGS-SETUP]")) #+end_src +#+caption[Fix engraving of symbolic color names]: +#+caption: Fix engraving of symbolic colors names. +#+name: lst:ensure-engrave-faces-with-latex-face-apply-fix +#+begin_src emacs-lisp + (when (and (ensure-package-installation 'engrave-faces) + (require 'engrave-faces-latex nil t)) + (defun engrave-faces-latex--color (color) + "Convert COLOR loosely to a string of six hexadecimal digits." + (if (char-equal ?# (aref color 0)) + (substring color 1 7) + (apply 'format "%02x%02x%02x" + (mapcar (lambda (c) (ash c -8)) + (color-values color))))) + + (defun engrave-faces-latex-face-apply-override (faces content) + "Convert attributes of FACES to LaTeX commands applied to CONTENT." + (let ((attrs (engrave-faces-merge-attributes faces))) + (let ((bg (plist-get attrs :background)) + (fg (plist-get attrs :foreground)) + (it (eql (plist-get attrs :slant) 'italic)) + (bl (member (plist-get attrs :weight) '(bold extra-bold))) + (st (plist-get attrs :strike-through))) + (concat + (when bg (concat "\\colorbox[HTML]{" + (engrave-faces-latex--color bg) "}{")) + (when fg (concat "\\textcolor[HTML]{" + (engrave-faces-latex--color fg) "}{")) + (when st "\\sout{") (when bl "\\textbf{") (when it "\\textit{") + content + (when bg "}") (when fg "}") (when st "}") (when bl "}") (when it "}")))))) + + (with-eval-after-load 'emacs + (defun toggle-advice (symbol where function &optional props) + "Toggle between states after `advice-remove' and `advice-add'." + (let ((how "%s `%s' advice `%s' %s `%s'")) + (if (advice-member-p function symbol) + (progn + (message how "Removal of" where function "from" symbol) + (advice-remove symbol function)) + (message how "Addition of" where function "to" symbol) + (advice-add symbol where function props)))) + + (defun toggle-engrave-faces-latex-face-apply-override () + "Toggle `engrave-faces-latex-face-apply' advice." + (interactive) + (toggle-advice 'engrave-faces-latex-face-apply + :override #'engrave-faces-latex-face-apply-override)) + + (toggle-engrave-faces-latex-face-apply-override)) +#+end_src + +#+caption[Fix engraving of horizontal/vertical spacing in multiline docstrings]: +#+caption: Fix engraving of horizontal and vertical spacing in multiple line +#+caption: documentation strings. +#+name: lst:ensure-engrave-faces-with-latex-face-mapper-fix +#+begin_src emacs-lisp + (when (and (ensure-package-installation 'engrave-faces) + (require 'engrave-faces-latex nil t)) + (defun engrave-faces-latex-face-mapper-override (faces content) + "Create a LaTeX representation of CONTENT with FACES applied." + (let* ((style (engrave-faces-preset-style faces)) + (protected-content + (funcall + (if (and engrave-faces-latex-mathescape + (eq 'font-lock-comment-face (car style))) + #'engrave-faces-latex--protect-content-mathescape + #'engrave-faces-latex--protect-content) + content))) + ;; Wrap groups of "words joined by blank characters" in LaTeX commands. + ;; Do not wrap newlines and other whitespace between those groups. + (let ((regexp (rx (or (group-n 1 (+ graph ) (* (+ blank) (+ graph))) + (group-n 2 (+ (any "\n" space)))))) + (slug (when (and style + (eq engrave-faces-latex-output-style 'preset)) + (plist-get (cdr style) :slug))) + (start 0) (stack)) + (while (string-match regexp protected-content start) + (setq start (match-end 0)) + (when-let ((pc (match-string 1 protected-content))) + (if (stringp slug) + (push (concat "\\EF" slug "{" pc "}") stack) + (push (engrave-faces-latex-face-apply faces pc) stack))) + (when-let ((pc (match-string 2 protected-content))) + (push pc stack))) + (apply #'concat (nreverse stack)))))) + + (with-eval-after-load 'emacs + (defun toggle-engrave-faces-latex-face-mapper-override () + "Toggle `engrave-faces-latex-face-mapper' advice." + (interactive) + (toggle-advice 'engrave-faces-latex-face-mapper + :override #'engrave-faces-latex-face-mapper-override)) + + (toggle-engrave-faces-latex-face-mapper-override)) +#+end_src + #+caption[Emacs setup to use =engrave-faces-latex= in =org-mode= smartly]: #+caption: Emacs setup to use =engrave-faces-latex= in =org-mode= smartly. #+name: lst:ox-engraved-emacs-lisp-setup