From: Timothy <tecosaur@gmail.com>
To: Ihor Radchenko <yantar92@gmail.com>
Cc: emacs-orgmode@gnu.org, Daniel Fleischer <danflscr@gmail.com>,
Nicolas Goaziou <mail@nicolasgoaziou.fr>
Subject: Re: [PATCH] New LaTeX code export option: engraved
Date: Fri, 06 May 2022 00:13:56 +0800 [thread overview]
Message-ID: <87sfpoyn0l.fsf@gmail.com> (raw)
In-Reply-To: <87v8ukyo94.fsf@gmail.com>
[-- 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
next prev parent reply other threads:[~2022-05-05 16:26 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.orgmode.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87sfpoyn0l.fsf@gmail.com \
--to=tecosaur@gmail.com \
--cc=danflscr@gmail.com \
--cc=emacs-orgmode@gnu.org \
--cc=mail@nicolasgoaziou.fr \
--cc=yantar92@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).