Compare commits
3 Commits
b4fd5335b1
...
e6957f2434
Author | SHA1 | Date | |
---|---|---|---|
e6957f2434 | |||
f067cda41e | |||
7b6177ccf8 |
96
README.org
96
README.org
@ -352,33 +352,9 @@ recommendation of [[info:emacs#Saving Customizations][saving customizations (inf
|
|||||||
(when (eq window-system 'ns)
|
(when (eq window-system 'ns)
|
||||||
(add-to-list 'initial-frame-alist '(height . 51))
|
(add-to-list 'initial-frame-alist '(height . 51))
|
||||||
(add-to-list 'initial-frame-alist '(width . 180)))
|
(add-to-list 'initial-frame-alist '(width . 180)))
|
||||||
#+end_src
|
|
||||||
|
|
||||||
#+caption[Handle ~user-emacs-directory~ site-lisp directories as packages]:
|
(when (file-exists-p custom-file)
|
||||||
#+caption: Handle ~user-emacs-directory~ site-lisp directories as packages.
|
(load custom-file))
|
||||||
#+name: lst:site-lisp-packages
|
|
||||||
#+begin_src emacs-lisp -n :results silent
|
|
||||||
(with-eval-after-load 'emacs
|
|
||||||
;; https://www.emacswiki.org/emacs/LoadPath
|
|
||||||
;; Make user-emacs-directory site-lisp directories look like packages.
|
|
||||||
(mapc (apply-partially 'add-to-list 'load-path)
|
|
||||||
(cl-remove-duplicates
|
|
||||||
(mapcar (lambda (file)
|
|
||||||
(directory-file-name (file-name-directory file)))
|
|
||||||
(directory-files-recursively
|
|
||||||
(expand-file-name "site-lisp" user-emacs-directory) "\\.el$"))
|
|
||||||
:test #'string=))
|
|
||||||
|
|
||||||
;; See package.el for how to use `loaddefs-generate-dir'.
|
|
||||||
(defun make-loaddefs-in-buffer-directory ()
|
|
||||||
"Make or update the autoloads in the directory of the visited file."
|
|
||||||
(interactive)
|
|
||||||
(let ((dir (directory-file-name (file-name-directory (buffer-file-name))))
|
|
||||||
(name (file-name-base (directory-file-name
|
|
||||||
(file-name-directory (buffer-file-name))))))
|
|
||||||
(loaddefs-generate dir
|
|
||||||
(expand-file-name (format "%s-autoloads.el" name) dir)
|
|
||||||
nil nil nil 'generate-full))))
|
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
* [[info:emacs#Package Installation][Install the selected packages (info)]]
|
* [[info:emacs#Package Installation][Install the selected packages (info)]]
|
||||||
@ -2335,7 +2311,7 @@ of the [[info:org#Top][Org (info)]] manual.
|
|||||||
:CUSTOM_ID: sec:setup-org
|
:CUSTOM_ID: sec:setup-org
|
||||||
:END:
|
:END:
|
||||||
|
|
||||||
I have split the initial [[https://orgmode.org/][Org-mode]] setup over fourteen listings. Here, follows a
|
I have split the initial [[https://orgmode.org/][Org-mode]] setup over thirteen listings. Here, follows a
|
||||||
list detailing and motivating each listing:
|
list detailing and motivating each listing:
|
||||||
1. Listing [[lst:set-org-options]] handles basic [[https://orgmode.org/][Org-mode]] options.
|
1. Listing [[lst:set-org-options]] handles basic [[https://orgmode.org/][Org-mode]] options.
|
||||||
2. Listing [[lst:undo-org-ctags]] undoes ~org-ctags~. See [[https://list.orgmode.org/87mt43agk6.fsf@localhost/][org-ctags land grab]] for
|
2. Listing [[lst:undo-org-ctags]] undoes ~org-ctags~. See [[https://list.orgmode.org/87mt43agk6.fsf@localhost/][org-ctags land grab]] for
|
||||||
@ -2345,26 +2321,22 @@ list detailing and motivating each listing:
|
|||||||
4. Listing [[lst:fake-org-babel-functions]] adds =org-babel-execute:<LANGUAGE>=
|
4. Listing [[lst:fake-org-babel-functions]] adds =org-babel-execute:<LANGUAGE>=
|
||||||
functions to silence src_emacs-lisp[:results silent]{(find-library
|
functions to silence src_emacs-lisp[:results silent]{(find-library
|
||||||
"org-lint")}.
|
"org-lint")}.
|
||||||
5. Listing [[lst:ob-tangle-plus]] extends [[info:org#Noweb Reference Syntax][source code export (info)]] with the
|
5. Listing [[lst:set-org-link-options]] handles [[https://orgmode.org/][Org-mode]] options specific to
|
||||||
possibility to tangle of for instance Emacs Lisp files (or other programming
|
|
||||||
mode files) into a directory specified by ~org-babel-post-tangle-dir~ which
|
|
||||||
~toggle-post-tangle-hook-dir-usage~ may change.
|
|
||||||
6. Listing [[lst:set-org-link-options]] handles [[https://orgmode.org/][Org-mode]] options specific to
|
|
||||||
[[info:org#Hyperlinks][hyperlinks (info)]].
|
[[info:org#Hyperlinks][hyperlinks (info)]].
|
||||||
7. Listing [[lst:setup-org-mode-map-1]] and [[lst:setup-org-mode-map-2]] extend the
|
6. Listing [[lst:setup-org-mode-map-1]] and [[lst:setup-org-mode-map-2]] extend the
|
||||||
=org-mode-map= with useful key-bindings.
|
=org-mode-map= with useful key-bindings.
|
||||||
8. Listing [[lst:setup-org-src]] facilitates [[info:org#Editing Source Code][editing source code blocks]], and it
|
7. Listing [[lst:setup-org-src]] facilitates [[info:org#Editing Source Code][editing source code blocks]], and it
|
||||||
provides functions to change the indentation of all =org-src-mode= blocks.
|
provides functions to change the indentation of all =org-src-mode= blocks.
|
||||||
9. Listing [[lst:setup-ob-python]] allows to pretty-print Python session source
|
8. Listing [[lst:setup-ob-python]] allows to pretty-print Python session source
|
||||||
block values with [[https://github.com/psf/black#readme][black]] instead of [[https://docs.python.org/3/library/pprint.html][pprint]]. This snippet may break in the
|
block values with [[https://github.com/psf/black#readme][black]] instead of [[https://docs.python.org/3/library/pprint.html][pprint]]. This snippet may break in the
|
||||||
future, because it sets =org-babel-python--def-format-value= which is a
|
future, because it sets =org-babel-python--def-format-value= which is a
|
||||||
constant declared "private" by two dashes in its name!
|
constant declared "private" by two dashes in its name!
|
||||||
10. Listing [[lst:set-org-export-options]] selects the =non-intrusive= expert user
|
9. Listing [[lst:set-org-export-options]] selects the =non-intrusive= expert user
|
||||||
interface for export dispatching.
|
interface for export dispatching.
|
||||||
11. Listing [[lst:setup-org-for-lualatex-export]] and
|
10. Listing [[lst:setup-org-for-lualatex-export]] and
|
||||||
[[lst:set-ox-latex-options-for-lualatex-export]] configure [[https://orgmode.org/][Org-mode]] to generate
|
[[lst:set-ox-latex-options-for-lualatex-export]] configure [[https://orgmode.org/][Org-mode]] to generate
|
||||||
output for the LuaLaTeX compiler.
|
output for the LuaLaTeX compiler.
|
||||||
12. Listing [[lst:setup-org-latex-classes]] defines [[info:org#LaTeXspecificexportsettings][org-latex-classes (info)]] for
|
11. Listing [[lst:setup-org-latex-classes]] defines [[info:org#LaTeXspecificexportsettings][org-latex-classes (info)]] for
|
||||||
backward compatibility. Type {{{kbd(C-h v org-latex-classes)}}} for an
|
backward compatibility. Type {{{kbd(C-h v org-latex-classes)}}} for an
|
||||||
explanation of the code in listing [[lst:setup-org-latex-classes]].
|
explanation of the code in listing [[lst:setup-org-latex-classes]].
|
||||||
|
|
||||||
@ -2473,52 +2445,6 @@ list detailing and motivating each listing:
|
|||||||
"NO-OP to silence warnings." nil)
|
"NO-OP to silence warnings." nil)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
#+caption[Change the =org-babel-tangle= destination to a specific directory]:
|
|
||||||
#+caption: Change the =org-babel-tangle= destination to a specific directory.
|
|
||||||
#+name: lst:ob-tangle-plus
|
|
||||||
#+begin_src emacs-lisp -n :results silent
|
|
||||||
(with-eval-after-load 'emacs
|
|
||||||
;; Modified from https://emacs.stackexchange.com/a/61364 which replies to
|
|
||||||
;; https://emacs.stackexchange.com/questions/61359/
|
|
||||||
;; "How to specify a directory to tangle all code blocks into".
|
|
||||||
;; Org usage example, add a line: #+property: tangle-dir ./site-lisp/
|
|
||||||
|
|
||||||
(defcustom org-babel-post-tangle-dir nil
|
|
||||||
"Destination directory used by `dir+org-babel-post-tangle'.
|
|
||||||
Is subject to change by `toggle-post-tangle-hook-dir-usage'."
|
|
||||||
:group 'org-babel)
|
|
||||||
|
|
||||||
(defcustom org-babel-post-tangle-dir-modes '(emacs-lisp-mode)
|
|
||||||
"Modes for which `dir+org-babel-post-tangle' does what it has to do."
|
|
||||||
:group 'org-babel)
|
|
||||||
|
|
||||||
(defun org-babel-post-tangle-into ()
|
|
||||||
"Function to hook on `org-babel-post-tangle-hook'."
|
|
||||||
(when (and org-babel-post-tangle-dir
|
|
||||||
(derived-mode-p org-babel-post-tangle-dir-modes))
|
|
||||||
(let ((bfn (buffer-file-name)))
|
|
||||||
(unless (or (string-suffix-p "init.el" bfn)
|
|
||||||
(string-suffix-p "dir-locals.el" bfn))
|
|
||||||
(message "Tangle file `%S' into `%S'"
|
|
||||||
bfn org-babel-post-tangle-dir)
|
|
||||||
(rename-file bfn org-babel-post-tangle-dir t)))))
|
|
||||||
|
|
||||||
(defun org-babel-toggle-post-tangle-into ()
|
|
||||||
"Toggle tangling to `org-babel-post-tangle-dir'."
|
|
||||||
(interactive)
|
|
||||||
(if (member 'org-babel-post-tangle-into org-babel-post-tangle-hook)
|
|
||||||
(progn
|
|
||||||
(setq org-babel-post-tangle-dir nil)
|
|
||||||
(message "Disable tangling (into `%S')" org-babel-post-tangle-dir)
|
|
||||||
(remove-hook 'org-babel-post-tangle-hook #'org-babel-post-tangle-into))
|
|
||||||
(setq org-babel-post-tangle-dir
|
|
||||||
(expand-file-name (org-entry-get nil "tangle-dir" t)
|
|
||||||
user-emacs-directory))
|
|
||||||
(message "Enable tangling (into `%S')" org-babel-post-tangle-dir)
|
|
||||||
(add-hook 'org-babel-post-tangle-hook
|
|
||||||
#'org-babel-post-tangle-into))))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
#+caption[Set =org-link= options]:
|
#+caption[Set =org-link= options]:
|
||||||
#+caption: Set =org-link= options.
|
#+caption: Set =org-link= options.
|
||||||
#+name: lst:set-org-link-options
|
#+name: lst:set-org-link-options
|
||||||
@ -2528,7 +2454,7 @@ Is subject to change by `toggle-post-tangle-hook-dir-usage'."
|
|||||||
;; behavior. Set `org-link-descriptive' interactively by calling
|
;; behavior. Set `org-link-descriptive' interactively by calling
|
||||||
;; `org-toggle-link-display'.
|
;; `org-toggle-link-display'.
|
||||||
(setopt org-link-descriptive t
|
(setopt org-link-descriptive t
|
||||||
org-link-file-path-type 'relative
|
org-link-file-path-type 'adaptive
|
||||||
org-link-search-must-match-exact-headline nil))
|
org-link-search-must-match-exact-headline nil))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
;;; org-index-capture --- dynamic block example -*- lexical-binding: t; -*-
|
|
||||||
;;; Blog: https://one-octet.dev/posts/org-mode-dynamic-index.html
|
|
||||||
|
|
||||||
(require 'org)
|
|
||||||
|
|
||||||
(declare-function org-element-map "org-element" (data types fun &optional info first-match no-recursion with-affiliated))
|
|
||||||
(declare-function org-element-parse-buffer "org-element" (&optional granularity visible-only keep-deferred))
|
|
||||||
(declare-function org-element-property "org-element-ast" (property node))
|
|
||||||
|
|
||||||
(defun org-index-extract-infos (file-path)
|
|
||||||
"Extract all information for an index from FILE-PATH."
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert-file-contents file-path)
|
|
||||||
(append
|
|
||||||
(org-element-map (org-element-parse-buffer) 'keyword
|
|
||||||
(lambda (keyword)
|
|
||||||
(list (org-element-property :key keyword)
|
|
||||||
(org-element-property :value keyword))))
|
|
||||||
(list (list "FILE-PATH" file-path)
|
|
||||||
(list "FILE-FULL-PATH" (expand-file-name file-path))))))
|
|
||||||
|
|
||||||
(defun org-index-list-files-path (directory)
|
|
||||||
"Get the DIRECTORY based names of all `.org' files in DIRECTORY."
|
|
||||||
(mapcar (lambda (file-name)
|
|
||||||
(file-name-concat directory file-name))
|
|
||||||
(directory-files directory nil ".org$")))
|
|
||||||
|
|
||||||
(defun org-index-sort-file-alists (alists)
|
|
||||||
"Sort a list of `.org' information alists by date."
|
|
||||||
(sort alists (lambda (file-a file-b)
|
|
||||||
(string> (cadr (assoc "DATE" file-a))
|
|
||||||
(cadr (assoc "DATE" file-b))))))
|
|
||||||
|
|
||||||
(defun org-index-spec-make (alist)
|
|
||||||
"Call `format-spec-make' using an `.org' file ALIST."
|
|
||||||
(let ((author (or (cadr (assoc "AUTHOR" alist)) "NO-AUTHOR"))
|
|
||||||
(creator (or (cadr (assoc "CREATOR" alist)) "NO-CREATOR"))
|
|
||||||
(date (or (cadr (assoc "DATE" alist)) "1999.12.31"))
|
|
||||||
(description (or (cadr (assoc "DESCRIPTION" alist)) "NO-DESCRIPTION"))
|
|
||||||
(file-full-path (cadr (assoc "FILE-FULL-PATH" alist)))
|
|
||||||
(file-path (cadr (assoc "FILE-PATH" alist)))
|
|
||||||
(language (or (cadr (assoc "LANGUAGE" alist)) "NO-LANGUAGE"))
|
|
||||||
(options (or (cadr (assoc "OPTIONS" alist)) "NO-OPTIONS"))
|
|
||||||
(title (or (cadr (assoc "TITLE" alist)) "NO-TITLE")))
|
|
||||||
(format-spec-make ?a author ?c creator
|
|
||||||
?d date ?D description
|
|
||||||
?l language ?o options
|
|
||||||
?P file-full-path ?p file-path
|
|
||||||
?t title)))
|
|
||||||
|
|
||||||
(defun org-dblock-write:index (params)
|
|
||||||
"Write a directory index."
|
|
||||||
(let ((directory (or (plist-get params :directory )
|
|
||||||
(file-name-directory (buffer-file-name))))
|
|
||||||
(sort-recent (plist-get params :sort-recent))
|
|
||||||
(fmt (or (plist-get params :format) "- %d: [[file:%p][%t]]"))
|
|
||||||
(alists nil))
|
|
||||||
(if sort-recent
|
|
||||||
(setq alists (org-index-sort-file-alists
|
|
||||||
(mapcar
|
|
||||||
'org-index-extract-infos
|
|
||||||
(org-index-list-files-path directory))))
|
|
||||||
(setq alists (mapcar
|
|
||||||
'org-index-extract-infos
|
|
||||||
(org-index-list-files-path directory))))
|
|
||||||
(mapcar
|
|
||||||
(lambda (alist)
|
|
||||||
(insert (format-spec fmt (org-index-spec-make alist)) "\n"))
|
|
||||||
alists)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun org-index-insert-dblock (directory)
|
|
||||||
"Create a dynamic block capturing a directory index."
|
|
||||||
(interactive
|
|
||||||
(list (string-replace
|
|
||||||
(file-name-directory (buffer-file-name))
|
|
||||||
""
|
|
||||||
(expand-file-name (read-directory-name "Directory to index: ")))))
|
|
||||||
(org-create-dblock
|
|
||||||
(list :name "index"
|
|
||||||
:directory directory)))
|
|
||||||
|
|
||||||
(org-dynamic-block-define "index" 'org-index-insert-dblock)
|
|
||||||
|
|
||||||
(provide 'org-index-capture)
|
|
||||||
|
|
||||||
;;; org-index-capture.el ends here
|
|
@ -1,413 +0,0 @@
|
|||||||
;;; ox-my-html.el --- HTML Derived Backend -*- lexical-binding: t; -*-
|
|
||||||
|
|
||||||
;; Copyright (C) 2023 Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
;; Author: Carsten Dominik <carsten.dominik@gmail.com>
|
|
||||||
;; Jambunathan K <kjambunathan at gmail dot com>
|
|
||||||
;; Gerard Vermeulen <gerard.vermeulen AT posteo DOT net>
|
|
||||||
;; Maintainer: Gerard Vermeulen <gerard.vermeulen AT posteo DOT net>
|
|
||||||
;; Keywords: org, hypermedia
|
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
|
||||||
|
|
||||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
|
||||||
;; it under the terms of the GNU General Public License as published by
|
|
||||||
;; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
;; (at your option) any later version.
|
|
||||||
|
|
||||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
|
||||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
;; GNU General Public License for more details.
|
|
||||||
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
|
||||||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; This library implements a HTML derived backend for Org export:
|
|
||||||
;; 1. The function org-my-html-link is an edited org-html-link copy.
|
|
||||||
;; 2. The Org ox-beamer library shows how to code derived backends.
|
|
||||||
;; 3. It borrows code from https://emacs.stackexchange.com/a/57433 to
|
|
||||||
;; embed SVG images in exported HTML files.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'org-macs)
|
|
||||||
(org-assert-version)
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
(require 'ox-html)
|
|
||||||
|
|
||||||
|
|
||||||
;;; Define Backend
|
|
||||||
|
|
||||||
(org-export-define-derived-backend 'my-html 'html
|
|
||||||
:menu-entry
|
|
||||||
'(?h 1
|
|
||||||
((?M "As MY-HTML buffer" org-my-html-export-as-html)
|
|
||||||
(?m "As MY-HTML file" org-my-html-export-to-html)
|
|
||||||
(?O "As MY-HTML file and open"
|
|
||||||
(lambda (a s v b)
|
|
||||||
(if a (org-my-html-export-to-html t s v b)
|
|
||||||
(org-open-file (org-my-html-export-to-html nil s v b)))))))
|
|
||||||
:options-alist
|
|
||||||
'((:html-embed-svg-excludes "HTML_EMBED_SVG_EXCLUDES" nil
|
|
||||||
org-html-embed-svg-excludes split)
|
|
||||||
(:html-embed-svg-includes "HTML_EMBED_SVG_INCLUDES" nil
|
|
||||||
org-html-embed-svg-includes split)
|
|
||||||
(:with-html-svg-embedding nil "html-embed-svg" org-html-embed-svg))
|
|
||||||
:translate-alist
|
|
||||||
'((link . org-my-html-link)))
|
|
||||||
|
|
||||||
|
|
||||||
;;; User Configuration Variables
|
|
||||||
|
|
||||||
;;;; Links :: Embed SVG
|
|
||||||
|
|
||||||
(defcustom org-html-embed-svg nil
|
|
||||||
"Non-nil means embed SVG images into exported HTML pages,
|
|
||||||
otherwise link to SVG images from exported HTML pages.
|
|
||||||
|
|
||||||
This option can also be set in Org files with
|
|
||||||
#+OPTIONS: html-embed-svg:t
|
|
||||||
or
|
|
||||||
#+OPTIONS: html-embed-svg:nil
|
|
||||||
to enable or disable SVG embedding in exported HTML."
|
|
||||||
:group 'org-export-html
|
|
||||||
:version "30.0"
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom org-html-embed-svg-excludes nil
|
|
||||||
"List of SVG files to exclude from SVG embedding.
|
|
||||||
|
|
||||||
This option overrules an `org-html-embed-svg' non-nil value.
|
|
||||||
|
|
||||||
It can also be set with the HTML_EMBED_SVG_EXCLUDES keyword."
|
|
||||||
:group 'org-export-html
|
|
||||||
:version "30.0"
|
|
||||||
:type '(repeat string)
|
|
||||||
:safe (lambda (x) (and (listp x) (cl-every #'stringp x))))
|
|
||||||
|
|
||||||
(defcustom org-html-embed-svg-includes nil
|
|
||||||
"List of SVG files to include in SVG embedding.
|
|
||||||
|
|
||||||
This option overrules an `org-html-embed-svg' nil value.
|
|
||||||
|
|
||||||
It can also be set with the HTML_EMBED_SVG_INCLUDES keyword."
|
|
||||||
:group 'org-export-html
|
|
||||||
:version "30.0"
|
|
||||||
:type '(repeat string)
|
|
||||||
:safe (lambda (x) (and (listp x) (cl-every #'stringp x))))
|
|
||||||
|
|
||||||
;;; Internal Functions
|
|
||||||
|
|
||||||
(defun org-my-html--embed-svg-p (link path info)
|
|
||||||
"Check whether LINK and INFO specify to embed the SVG file named PATH.
|
|
||||||
LINK must have no contents and link to an SVG file. INFO may contain
|
|
||||||
lists of SVG files to include in and/or to exclude from embedding."
|
|
||||||
(and (not (org-element-contents link))
|
|
||||||
(let ((case-fold-search t))
|
|
||||||
(string-match-p ".svg\\'" (org-element-property :path link)))
|
|
||||||
(or (and (plist-get info :with-html-svg-embedding)
|
|
||||||
(not (member path (plist-get info :html-embed-svg-excludes))))
|
|
||||||
(and (not (plist-get info :with-html-svg-embedding))
|
|
||||||
(member path (plist-get info :html-embed-svg-includes))))))
|
|
||||||
|
|
||||||
(defun org-my-html-svg-contents (path)
|
|
||||||
"Return the SVG contents of the file named PATH."
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert-file-contents path)
|
|
||||||
;; Delete text preceding something starting as an SVG root element.
|
|
||||||
;; The intent is to remove XML declarations (and XML comments).
|
|
||||||
;; This breaks in case of a preceding XML comment with <svg inside
|
|
||||||
;; or a preceding XML element with an SVG element inside.
|
|
||||||
;; See https://emacs.stackexchange.com/a/57433 for the original code.
|
|
||||||
(let ((case-fold-search t))
|
|
||||||
(unless (search-forward "<svg" nil 'noerror)
|
|
||||||
(user-error "Can't find a root SVG start tag in file `%s'." path)))
|
|
||||||
(delete-region (point-min) (match-beginning 0))
|
|
||||||
(buffer-string)))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Transcode Functions
|
|
||||||
|
|
||||||
;;;; Link
|
|
||||||
|
|
||||||
(defun org-my-html-link (link desc info)
|
|
||||||
"Transcode a LINK object from Org to HTML.
|
|
||||||
DESC is the description part of the link, or the empty string.
|
|
||||||
INFO is a plist holding contextual information. See
|
|
||||||
`org-export-data'. This function can embed or link SVG images
|
|
||||||
contrary to `org-html-link' which can only link such images."
|
|
||||||
(let* ((html-ext (plist-get info :html-extension))
|
|
||||||
(dot (when (> (length html-ext) 0) "."))
|
|
||||||
(link-org-files-as-html-maybe
|
|
||||||
(lambda (raw-path info)
|
|
||||||
;; Treat links to `file.org' as links to `file.html', if
|
|
||||||
;; needed. See `org-html-link-org-files-as-html'.
|
|
||||||
(save-match-data
|
|
||||||
(cond
|
|
||||||
((and (plist-get info :html-link-org-files-as-html)
|
|
||||||
(let ((case-fold-search t))
|
|
||||||
(string-match "\\(.+\\)\\.org\\(?:\\.gpg\\)?$" raw-path)))
|
|
||||||
(concat (match-string 1 raw-path) dot html-ext))
|
|
||||||
(t raw-path)))))
|
|
||||||
(type (org-element-property :type link))
|
|
||||||
(raw-path (org-element-property :path link))
|
|
||||||
;; Ensure DESC really exists, or set it to nil.
|
|
||||||
(desc (org-string-nw-p desc))
|
|
||||||
(path
|
|
||||||
(cond
|
|
||||||
((member type '("http" "https" "ftp" "mailto" "news"))
|
|
||||||
(url-encode-url (concat type ":" raw-path)))
|
|
||||||
((string= "file" type)
|
|
||||||
;; During publishing, turn absolute file names belonging
|
|
||||||
;; to base directory into relative file names. Otherwise,
|
|
||||||
;; append "file" protocol to absolute file name.
|
|
||||||
(setq raw-path
|
|
||||||
(org-export-file-uri
|
|
||||||
(org-publish-file-relative-name raw-path info)))
|
|
||||||
;; Possibly append `:html-link-home' to relative file
|
|
||||||
;; name.
|
|
||||||
(let ((home (and (plist-get info :html-link-home)
|
|
||||||
(org-trim (plist-get info :html-link-home)))))
|
|
||||||
(when (and home
|
|
||||||
(plist-get info :html-link-use-abs-url)
|
|
||||||
(file-name-absolute-p raw-path))
|
|
||||||
(setq raw-path (concat (file-name-as-directory home) raw-path))))
|
|
||||||
;; Maybe turn ".org" into ".html".
|
|
||||||
(setq raw-path (funcall link-org-files-as-html-maybe raw-path info))
|
|
||||||
;; Add search option, if any. A search option can be
|
|
||||||
;; relative to a custom-id, a headline title, a name or
|
|
||||||
;; a target.
|
|
||||||
(let ((option (org-element-property :search-option link)))
|
|
||||||
(if (not option) raw-path
|
|
||||||
(let ((path (org-element-property :path link)))
|
|
||||||
(concat raw-path
|
|
||||||
"#"
|
|
||||||
(org-publish-resolve-external-link option path t))))))
|
|
||||||
(t raw-path)))
|
|
||||||
(attributes-plist
|
|
||||||
(org-combine-plists
|
|
||||||
;; Extract attributes from parent's paragraph. HACK: Only
|
|
||||||
;; do this for the first link in parent (inner image link
|
|
||||||
;; for inline images). This is needed as long as
|
|
||||||
;; attributes cannot be set on a per link basis.
|
|
||||||
(let* ((parent (org-export-get-parent-element link))
|
|
||||||
(link (let ((container (org-export-get-parent link)))
|
|
||||||
(if (and (eq 'link (org-element-type container))
|
|
||||||
(org-html-inline-image-p link info))
|
|
||||||
container
|
|
||||||
link))))
|
|
||||||
(and (eq link (org-element-map parent 'link #'identity info t))
|
|
||||||
(org-export-read-attribute :attr_html parent)))
|
|
||||||
;; Also add attributes from link itself. Currently, those
|
|
||||||
;; need to be added programmatically before `org-my-html-link'
|
|
||||||
;; is invoked, for example, by backends building upon HTML
|
|
||||||
;; export.
|
|
||||||
(org-export-read-attribute :attr_html link)))
|
|
||||||
(attributes
|
|
||||||
(let ((attr (org-html--make-attribute-string attributes-plist)))
|
|
||||||
(if (org-string-nw-p attr) (concat " " attr) ""))))
|
|
||||||
(cond
|
|
||||||
;; Link type is handled by a special function.
|
|
||||||
((org-export-custom-protocol-maybe link desc 'html info))
|
|
||||||
;; Embed SVG.
|
|
||||||
((org-my-html--embed-svg-p link path info)
|
|
||||||
(org-my-html-svg-contents path))
|
|
||||||
;; Image file.
|
|
||||||
((and (plist-get info :html-inline-images)
|
|
||||||
(org-export-inline-image-p
|
|
||||||
link (plist-get info :html-inline-image-rules)))
|
|
||||||
(org-html--format-image path attributes-plist info))
|
|
||||||
;; Radio target: Transcode target's contents and use them as
|
|
||||||
;; link's description.
|
|
||||||
((string= type "radio")
|
|
||||||
(let ((destination (org-export-resolve-radio-link link info)))
|
|
||||||
(if (not destination) desc
|
|
||||||
(format "<a href=\"#%s\"%s>%s</a>"
|
|
||||||
(org-export-get-reference destination info)
|
|
||||||
attributes
|
|
||||||
desc))))
|
|
||||||
;; Links pointing to a headline: Find destination and build
|
|
||||||
;; appropriate referencing command.
|
|
||||||
((member type '("custom-id" "fuzzy" "id"))
|
|
||||||
(let ((destination (if (string= type "fuzzy")
|
|
||||||
(org-export-resolve-fuzzy-link link info)
|
|
||||||
(org-export-resolve-id-link link info))))
|
|
||||||
(pcase (org-element-type destination)
|
|
||||||
;; ID link points to an external file.
|
|
||||||
(`plain-text
|
|
||||||
(let ((fragment (concat org-html--id-attr-prefix path))
|
|
||||||
;; Treat links to ".org" files as ".html", if needed.
|
|
||||||
(path (funcall link-org-files-as-html-maybe
|
|
||||||
destination info)))
|
|
||||||
(format "<a href=\"%s#%s\"%s>%s</a>"
|
|
||||||
path fragment attributes (or desc destination))))
|
|
||||||
;; Fuzzy link points nowhere.
|
|
||||||
(`nil
|
|
||||||
(format "<i>%s</i>"
|
|
||||||
(or desc
|
|
||||||
(org-export-data
|
|
||||||
(org-element-property :raw-link link) info))))
|
|
||||||
;; Link points to a headline.
|
|
||||||
(`headline
|
|
||||||
(let ((href (org-html--reference destination info))
|
|
||||||
;; What description to use?
|
|
||||||
(desc
|
|
||||||
;; Case 1: Headline is numbered and LINK has no
|
|
||||||
;; description. Display section number.
|
|
||||||
(if (and (org-export-numbered-headline-p destination info)
|
|
||||||
(not desc))
|
|
||||||
(mapconcat #'number-to-string
|
|
||||||
(org-export-get-headline-number
|
|
||||||
destination info) ".")
|
|
||||||
;; Case 2: Either the headline is un-numbered or
|
|
||||||
;; LINK has a custom description. Display LINK's
|
|
||||||
;; description or headline's title.
|
|
||||||
(or desc
|
|
||||||
(org-export-data
|
|
||||||
(org-element-property :title destination) info)))))
|
|
||||||
(format "<a href=\"#%s\"%s>%s</a>" href attributes desc)))
|
|
||||||
;; Fuzzy link points to a target or an element.
|
|
||||||
(_
|
|
||||||
(if (and destination
|
|
||||||
(memq (plist-get info :with-latex) '(mathjax t))
|
|
||||||
(eq 'latex-environment (org-element-type destination))
|
|
||||||
(eq 'math (org-latex--environment-type destination)))
|
|
||||||
;; Caption and labels are introduced within LaTeX
|
|
||||||
;; environment. Use "ref" or "eqref" macro, depending on user
|
|
||||||
;; preference to refer to those in the document.
|
|
||||||
(format (plist-get info :html-equation-reference-format)
|
|
||||||
(org-html--reference destination info))
|
|
||||||
(let* ((ref (org-html--reference destination info))
|
|
||||||
(org-html-standalone-image-predicate
|
|
||||||
#'org-html--has-caption-p)
|
|
||||||
(counter-predicate
|
|
||||||
(if (eq 'latex-environment (org-element-type destination))
|
|
||||||
#'org-html--math-environment-p
|
|
||||||
#'org-html--has-caption-p))
|
|
||||||
(number
|
|
||||||
(cond
|
|
||||||
(desc nil)
|
|
||||||
((org-html-standalone-image-p destination info)
|
|
||||||
(org-export-get-ordinal
|
|
||||||
(org-element-map destination 'link #'identity info t)
|
|
||||||
info '(link) 'org-html-standalone-image-p))
|
|
||||||
(t (org-export-get-ordinal
|
|
||||||
destination info nil counter-predicate))))
|
|
||||||
(desc
|
|
||||||
(cond (desc)
|
|
||||||
((not number) "No description for this link")
|
|
||||||
((numberp number) (number-to-string number))
|
|
||||||
(t (mapconcat #'number-to-string number ".")))))
|
|
||||||
(format "<a href=\"#%s\"%s>%s</a>" ref attributes desc)))))))
|
|
||||||
;; Coderef: replace link with the reference name or the
|
|
||||||
;; equivalent line number.
|
|
||||||
((string= type "coderef")
|
|
||||||
(let ((fragment (concat "coderef-" (org-html-encode-plain-text path))))
|
|
||||||
(format "<a href=\"#%s\" %s%s>%s</a>"
|
|
||||||
fragment
|
|
||||||
(format "class=\"coderef\" onmouseover=\"CodeHighlightOn(this, \
|
|
||||||
'%s');\" onmouseout=\"CodeHighlightOff(this, '%s');\""
|
|
||||||
fragment fragment)
|
|
||||||
attributes
|
|
||||||
(format (org-export-get-coderef-format path desc)
|
|
||||||
(org-export-resolve-coderef path info)))))
|
|
||||||
;; External link with a description part.
|
|
||||||
((and path desc)
|
|
||||||
(format "<a href=\"%s\"%s>%s</a>"
|
|
||||||
(org-html-encode-plain-text path)
|
|
||||||
attributes
|
|
||||||
desc))
|
|
||||||
;; External link without a description part.
|
|
||||||
(path
|
|
||||||
(let ((path (org-html-encode-plain-text path)))
|
|
||||||
(format "<a href=\"%s\"%s>%s</a>" path attributes path)))
|
|
||||||
;; No path, only description. Try to do something useful.
|
|
||||||
(t
|
|
||||||
(format "<i>%s</i>" desc)))))
|
|
||||||
|
|
||||||
|
|
||||||
;;; End-user functions
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun org-my-html-export-as-html
|
|
||||||
(&optional async subtreep visible-only body-only ext-plist)
|
|
||||||
"Export current buffer to an HTML buffer.
|
|
||||||
|
|
||||||
If narrowing is active in the current buffer, only export its
|
|
||||||
narrowed part.
|
|
||||||
|
|
||||||
If a region is active, export that region.
|
|
||||||
|
|
||||||
A non-nil optional argument ASYNC means the process should happen
|
|
||||||
asynchronously. The resulting buffer should be accessible
|
|
||||||
through the `org-export-stack' interface.
|
|
||||||
|
|
||||||
When optional argument SUBTREEP is non-nil, export the sub-tree
|
|
||||||
at point, extracting information from the headline properties
|
|
||||||
first.
|
|
||||||
|
|
||||||
When optional argument VISIBLE-ONLY is non-nil, don't export
|
|
||||||
contents of hidden elements.
|
|
||||||
|
|
||||||
When optional argument BODY-ONLY is non-nil, only write code
|
|
||||||
between \"<body>\" and \"</body>\" tags.
|
|
||||||
|
|
||||||
EXT-PLIST, when provided, is a property list with external
|
|
||||||
parameters overriding Org default settings, but still inferior to
|
|
||||||
file-local settings.
|
|
||||||
|
|
||||||
Export is done in a buffer named \"*Org HTML PLUS Export*\", which
|
|
||||||
will be displayed when `org-export-show-temporary-export-buffer'
|
|
||||||
is non-nil."
|
|
||||||
(interactive)
|
|
||||||
(org-export-to-buffer 'my-html "*Org MY-HTML Export*"
|
|
||||||
async subtreep visible-only body-only ext-plist
|
|
||||||
(lambda () (set-auto-mode t))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun org-my-html-export-to-html
|
|
||||||
(&optional async subtreep visible-only body-only ext-plist)
|
|
||||||
"Export current buffer to an HTML file.
|
|
||||||
|
|
||||||
If narrowing is active in the current buffer, only export its
|
|
||||||
narrowed part.
|
|
||||||
|
|
||||||
If a region is active, export that region.
|
|
||||||
|
|
||||||
A non-nil optional argument ASYNC means the process should happen
|
|
||||||
asynchronously. The resulting file should be accessible through
|
|
||||||
the `org-export-stack' interface.
|
|
||||||
|
|
||||||
When optional argument SUBTREEP is non-nil, export the sub-tree
|
|
||||||
at point, extracting information from the headline properties
|
|
||||||
first.
|
|
||||||
|
|
||||||
When optional argument VISIBLE-ONLY is non-nil, don't export
|
|
||||||
contents of hidden elements.
|
|
||||||
|
|
||||||
When optional argument BODY-ONLY is non-nil, only write code
|
|
||||||
between \"<body>\" and \"</body>\" tags.
|
|
||||||
|
|
||||||
EXT-PLIST, when provided, is a property list with external
|
|
||||||
parameters overriding Org default settings, but still inferior to
|
|
||||||
file-local settings.
|
|
||||||
|
|
||||||
Return output file's name."
|
|
||||||
(interactive)
|
|
||||||
(let* ((extension (concat
|
|
||||||
(when (> (length org-html-extension) 0) ".")
|
|
||||||
(or (plist-get ext-plist :html-extension)
|
|
||||||
org-html-extension
|
|
||||||
"html")))
|
|
||||||
(file (org-export-output-file-name extension subtreep))
|
|
||||||
(org-export-coding-system org-html-coding-system))
|
|
||||||
(org-export-to-file 'my-html file
|
|
||||||
async subtreep visible-only body-only ext-plist)))
|
|
||||||
|
|
||||||
(provide 'ox-my-html)
|
|
||||||
|
|
||||||
;;; ox-my-html.el ends here
|
|
@ -1,483 +0,0 @@
|
|||||||
;;; ox-svg4css.el --- HTML Derived Backend -*- lexical-binding: t; -*-
|
|
||||||
|
|
||||||
;; Copyright (C) 2023 Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
;; Author: Gerard Vermeulen <gerard.vermeulen AT posteo DOT net>
|
|
||||||
;; Maintainer: Gerard Vermeulen <gerard.vermeulen AT posteo DOT net>
|
|
||||||
;; Keywords: org, hypermedia
|
|
||||||
|
|
||||||
;; See the Emacs ox-html library for its authors, maintainer and FSF
|
|
||||||
;; Copyright, since ox-svg4css contains a lot of code from ox-html.
|
|
||||||
|
|
||||||
;; This file is NOT part of GNU Emacs.
|
|
||||||
|
|
||||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
|
||||||
;; it under the terms of the GNU General Public License as published by
|
|
||||||
;; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
;; (at your option) any later version.
|
|
||||||
|
|
||||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
|
||||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
;; GNU General Public License for more details.
|
|
||||||
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
|
||||||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; This library implements an HTML derived backend for Org export.
|
|
||||||
;; It tries to address limitations of SVG images and CSS in HTML pages.
|
|
||||||
;; For each SVG image during HTML export:
|
|
||||||
;; 1. It checks `svg-as-object' and "image in-lining" whether to
|
|
||||||
;; embed the SVG image in an <object> tag.
|
|
||||||
;; 2. If not, it checks `svg-inclusion' and "image in-lining"
|
|
||||||
;; whether to copy the SVG contents to the HTML output.
|
|
||||||
;; 3. If not, it falls back to checking "image in-lining" whether to
|
|
||||||
;; embed the SVG image in an <img> tag (as any other image type).
|
|
||||||
;; 4. It is possible to set `svg-as-object' and/or `svg-inclusion':
|
|
||||||
;; - For each SVG link by means of "#+ATTR_HTML: :svg-as-object t"
|
|
||||||
;; or "#+ATTR_HTML: :svg-inclusion t".
|
|
||||||
;; - Within file scope by means of "#+OPTIONS: svg-as-object:t" or
|
|
||||||
;; "#+OPTIONS: svg-inclusion:t".
|
|
||||||
;; - Within toplevel scope by means of the options
|
|
||||||
;; `org-html-svg-as-object' or `org-html-svg-inclusion'.
|
|
||||||
;;
|
|
||||||
;; Caveats: the HTML output does not comply with W3C recommendations
|
|
||||||
;; after `svg-as-object' and/or `svg-inclusion' exports and it does not
|
|
||||||
;; comply with the Org Manual section "13.9.9 Images in HTML export"
|
|
||||||
;; after `svg-inclusion' exports.
|
|
||||||
;;
|
|
||||||
;; See: https://list.orgmode.org/c1eef10be815748d2103cb81bce08708@posteo.net/
|
|
||||||
;; where Cristian Moe has proposed to embed SVG images in <object> tags.
|
|
||||||
;; Ihor Radchenko and Max Nikulin have insisted on the use of special
|
|
||||||
;; "#+ATTR_HTML:" attributes to control the export options.
|
|
||||||
;;
|
|
||||||
;; I prefer enabling `:svg-as-object' over enabling `:svg-inclusion'.
|
|
||||||
;;
|
|
||||||
;; Relevant W3C documentation:
|
|
||||||
;;
|
|
||||||
;; Loading an SVG image by an HTML <embed>, <iframe> or <object> tag:
|
|
||||||
;; https://stackoverflow.com/a/12604286
|
|
||||||
;; https://svgwg.org/specs/integration/#referencing-modes
|
|
||||||
;; https://svgwg.org/specs/integration/#embedded-document-mode
|
|
||||||
;; https://svgwg.org/specs/integration/#dynamic-interactive-mode
|
|
||||||
;;
|
|
||||||
;; Four types of SVG document usage with their security implications:
|
|
||||||
;; https://www.w3.org/wiki/SVG_Security
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'org-macs)
|
|
||||||
(org-assert-version)
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
(require 'ox-html)
|
|
||||||
|
|
||||||
|
|
||||||
;;; Define Derived Backend
|
|
||||||
|
|
||||||
(org-export-define-derived-backend 'svg4css 'html
|
|
||||||
:menu-entry
|
|
||||||
'(?h 1
|
|
||||||
((?M "As SVG4CSS buffer" org-svg4css-export-as-html)
|
|
||||||
(?m "As SVG4CSS file" org-svg4css-export-to-html)
|
|
||||||
(?O "As SVG4CSS file and open"
|
|
||||||
(lambda (a s v b)
|
|
||||||
(if a (org-svg4css-export-to-html t s v b)
|
|
||||||
(org-open-file (org-svg4css-export-to-html nil s v b)))))))
|
|
||||||
:options-alist
|
|
||||||
'((:html-svg-as-object nil "svg-as-object" org-html-svg-as-object)
|
|
||||||
(:html-svg-inclusion nil "svg-inclusion" org-html-svg-inclusion))
|
|
||||||
:translate-alist
|
|
||||||
'((link . org-svg4css-link)))
|
|
||||||
|
|
||||||
|
|
||||||
;;; User Configuration Variables
|
|
||||||
|
|
||||||
(defcustom org-html-svg-as-object nil
|
|
||||||
"Non-nil means export SVG images in object tags when in-lining
|
|
||||||
applies, otherwise apply SVG image inclusion or apply the normal
|
|
||||||
export rules.
|
|
||||||
|
|
||||||
SVG images in object tags and CSS links in such images simply work.
|
|
||||||
Note: https://www.w3schools.com/tags/tag_object.asp prefers <img>
|
|
||||||
tag usage."
|
|
||||||
:group 'org-export-html
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom org-html-svg-inclusion nil
|
|
||||||
"Non-nil means copy SVG image contents to the HTML output when
|
|
||||||
in-lining applies, otherwise apply the normal export rules.
|
|
||||||
|
|
||||||
The HTML file including the SVG image contents has to include or
|
|
||||||
to link the CSS to let the SVG image and the CSS work together.
|
|
||||||
Note: SVG inclusion breaks \"13.9.9 Images in HTML export\"."
|
|
||||||
:group 'org-export-html
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom org-html-no-attribute-names '("svg-as-object" "svg-inclusion")
|
|
||||||
"List of HTML tag attribute names to exclude from the tags.
|
|
||||||
Those attributes control image scope export options."
|
|
||||||
:group 'org-export-html
|
|
||||||
:type '(repeat string))
|
|
||||||
|
|
||||||
;;; Internal Functions
|
|
||||||
|
|
||||||
(defun org-svg4css--make-attribute-string (attributes no-attribute-names)
|
|
||||||
"Return a list of attributes, as a string.
|
|
||||||
ATTRIBUTES is a plist where values are either strings or nil. An
|
|
||||||
attribute with a nil value will be omitted from the result.
|
|
||||||
NO-ATTRIBUTE-NAMES lists attribute names to omit from the result."
|
|
||||||
(let (output)
|
|
||||||
(dolist (item attributes (mapconcat 'identity (nreverse output) " "))
|
|
||||||
(cond ((null item) (pop output))
|
|
||||||
((symbolp item) (push (substring (symbol-name item) 1) output))
|
|
||||||
(t (let ((key (car output))
|
|
||||||
(value (replace-regexp-in-string
|
|
||||||
"\"" """ (org-html-encode-plain-text item))))
|
|
||||||
(if (member key no-attribute-names)
|
|
||||||
(pop output)
|
|
||||||
(setcar output (format "%s=\"%s\"" key value)))))))))
|
|
||||||
|
|
||||||
(defun org-svg4css--svg-as-object-p (link info attributes-plist)
|
|
||||||
"Check whether LINK links to an SVG image to embed in an <object> tag.
|
|
||||||
INFO is a communication channel and ATTRIBUTES-PLIST holds all attributes
|
|
||||||
relevant to LINK."
|
|
||||||
(and (plist-get info :html-inline-images)
|
|
||||||
(not (org-element-contents link))
|
|
||||||
(let ((case-fold-search t))
|
|
||||||
(string-match-p ".svg\\'" (org-element-property :path link)))
|
|
||||||
(org-export-inline-image-p
|
|
||||||
link (plist-get info :html-inline-image-rules))
|
|
||||||
(or (and (plist-get attributes-plist :svg-as-object))
|
|
||||||
(and (plist-get info :html-svg-as-object)
|
|
||||||
;; Next form returns `nil' when member has value `nil'.
|
|
||||||
(or (not (plist-member attributes-plist :svg-as-object))
|
|
||||||
(plist-get attributes-plist :svg-as-object))))))
|
|
||||||
|
|
||||||
(defun org-svg4css--svg-inclusion-p (link info attributes-plist)
|
|
||||||
"Check whether LINK links to an SVG image to include in the HTML output.
|
|
||||||
INFO is a communication channel and ATTRIBUTES-PLIST holds all attributes
|
|
||||||
relevant to LINK."
|
|
||||||
(and (plist-get info :html-inline-images)
|
|
||||||
(not (org-element-contents link))
|
|
||||||
(let ((case-fold-search t))
|
|
||||||
(string-match-p ".svg\\'" (org-element-property :path link)))
|
|
||||||
(org-export-inline-image-p
|
|
||||||
link (plist-get info :html-inline-image-rules))
|
|
||||||
(or (and (plist-get attributes-plist :svg-inclusion))
|
|
||||||
(and (plist-get info :html-svg-inclusion)
|
|
||||||
;; Next form returns `nil' when member has value `nil'.
|
|
||||||
(or (not (plist-member attributes-plist :svg-inclusion))
|
|
||||||
(plist-get attributes-plist :svg-inclusion))))))
|
|
||||||
|
|
||||||
(defun org-svg4css--format-svg-as-object (path attributes-plist)
|
|
||||||
"Return a string embedding the SVG image PATH in an <objec> tag."
|
|
||||||
(format "<object %s>
|
|
||||||
ARIA placeholder: see https://vecta.io/blog/best-way-to-embed-svg for ideas!
|
|
||||||
</object>" (org-svg4css--make-attribute-string
|
|
||||||
(org-combine-plists
|
|
||||||
(list :data path
|
|
||||||
:type "image/svg+xml")
|
|
||||||
attributes-plist)
|
|
||||||
org-html-no-attribute-names)))
|
|
||||||
|
|
||||||
(defun org-svg4css--format-svg-inclusion (path)
|
|
||||||
"Return the SVG contents of the file named PATH for inclusion."
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert-file-contents path)
|
|
||||||
;; Delete text preceding something starting as an SVG root element.
|
|
||||||
;; The intent is to remove XML declarations (and XML comments).
|
|
||||||
;; This breaks in case of a preceding XML comment with <svg inside
|
|
||||||
;; or a preceding XML element with an SVG element inside.
|
|
||||||
(let ((case-fold-search t))
|
|
||||||
(unless (search-forward "<svg" nil 'noerror)
|
|
||||||
(user-error "Can't find a root SVG start tag in file `%s'." path)))
|
|
||||||
(delete-region (point-min) (match-beginning 0))
|
|
||||||
(buffer-string)))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Transcode Functions
|
|
||||||
|
|
||||||
;;;; Link
|
|
||||||
|
|
||||||
(defun org-svg4css-link (link desc info)
|
|
||||||
"Transcode a LINK object from Org to HTML.
|
|
||||||
DESC is the description part of the link, or the empty string.
|
|
||||||
INFO is a plist holding contextual information. See
|
|
||||||
`org-export-data'."
|
|
||||||
(let* ((html-ext (plist-get info :html-extension))
|
|
||||||
(dot (when (> (length html-ext) 0) "."))
|
|
||||||
(link-org-files-as-html-maybe
|
|
||||||
(lambda (raw-path info)
|
|
||||||
;; Treat links to `file.org' as links to `file.html', if
|
|
||||||
;; needed. See `org-html-link-org-files-as-html'.
|
|
||||||
(save-match-data
|
|
||||||
(cond
|
|
||||||
((and (plist-get info :html-link-org-files-as-html)
|
|
||||||
(let ((case-fold-search t))
|
|
||||||
(string-match "\\(.+\\)\\.org\\(?:\\.gpg\\)?$" raw-path)))
|
|
||||||
(concat (match-string 1 raw-path) dot html-ext))
|
|
||||||
(t raw-path)))))
|
|
||||||
(type (org-element-property :type link))
|
|
||||||
(raw-path (org-element-property :path link))
|
|
||||||
;; Ensure DESC really exists, or set it to nil.
|
|
||||||
(desc (org-string-nw-p desc))
|
|
||||||
(path
|
|
||||||
(cond
|
|
||||||
((member type '("http" "https" "ftp" "mailto" "news"))
|
|
||||||
(url-encode-url (concat type ":" raw-path)))
|
|
||||||
((string= "file" type)
|
|
||||||
;; During publishing, turn absolute file names belonging
|
|
||||||
;; to base directory into relative file names. Otherwise,
|
|
||||||
;; append "file" protocol to absolute file name.
|
|
||||||
(setq raw-path
|
|
||||||
(org-export-file-uri
|
|
||||||
(org-publish-file-relative-name raw-path info)))
|
|
||||||
;; Possibly append `:html-link-home' to relative file
|
|
||||||
;; name.
|
|
||||||
(let ((home (and (plist-get info :html-link-home)
|
|
||||||
(org-trim (plist-get info :html-link-home)))))
|
|
||||||
(when (and home
|
|
||||||
(plist-get info :html-link-use-abs-url)
|
|
||||||
(file-name-absolute-p raw-path))
|
|
||||||
(setq raw-path (concat (file-name-as-directory home) raw-path))))
|
|
||||||
;; Maybe turn ".org" into ".html".
|
|
||||||
(setq raw-path (funcall link-org-files-as-html-maybe raw-path info))
|
|
||||||
;; Add search option, if any. A search option can be
|
|
||||||
;; relative to a custom-id, a headline title, a name or
|
|
||||||
;; a target.
|
|
||||||
(let ((option (org-element-property :search-option link)))
|
|
||||||
(if (not option) raw-path
|
|
||||||
(let ((path (org-element-property :path link)))
|
|
||||||
(concat raw-path
|
|
||||||
"#"
|
|
||||||
(org-publish-resolve-external-link option path t))))))
|
|
||||||
(t raw-path)))
|
|
||||||
(attributes-plist
|
|
||||||
(org-combine-plists
|
|
||||||
;; Extract attributes from parent's paragraph. HACK: Only
|
|
||||||
;; do this for the first link in parent (inner image link
|
|
||||||
;; for inline images). This is needed as long as
|
|
||||||
;; attributes cannot be set on a per link basis.
|
|
||||||
(let* ((parent (org-export-get-parent-element link))
|
|
||||||
(link (let ((container (org-export-get-parent link)))
|
|
||||||
(if (and (eq 'link (org-element-type container))
|
|
||||||
(org-html-inline-image-p link info))
|
|
||||||
container
|
|
||||||
link))))
|
|
||||||
(and (eq link (org-element-map parent 'link #'identity info t))
|
|
||||||
(org-export-read-attribute :attr_html parent)))
|
|
||||||
;; Also add attributes from link itself. Currently, those
|
|
||||||
;; need to be added programmatically before `org-html-link'
|
|
||||||
;; is invoked, for example, by backends building upon HTML
|
|
||||||
;; export.
|
|
||||||
(org-export-read-attribute :attr_html link)))
|
|
||||||
(attributes
|
|
||||||
(let ((attr (org-html--make-attribute-string attributes-plist)))
|
|
||||||
(if (org-string-nw-p attr) (concat " " attr) ""))))
|
|
||||||
(cond
|
|
||||||
;; Link type is handled by a special function.
|
|
||||||
((org-export-custom-protocol-maybe link desc 'html info))
|
|
||||||
;; SVG as object.
|
|
||||||
((org-svg4css--svg-as-object-p link info attributes-plist)
|
|
||||||
(org-svg4css--format-svg-as-object path attributes-plist))
|
|
||||||
;; SVG inclusion.
|
|
||||||
((org-svg4css--svg-inclusion-p link info attributes-plist)
|
|
||||||
(org-svg4css--format-svg-inclusion path))
|
|
||||||
;; Image file.
|
|
||||||
((and (plist-get info :html-inline-images)
|
|
||||||
(org-export-inline-image-p
|
|
||||||
link (plist-get info :html-inline-image-rules)))
|
|
||||||
(org-html--format-image path attributes-plist info))
|
|
||||||
;; Radio target: Transcode target's contents and use them as
|
|
||||||
;; link's description.
|
|
||||||
((string= type "radio")
|
|
||||||
(let ((destination (org-export-resolve-radio-link link info)))
|
|
||||||
(if (not destination) desc
|
|
||||||
(format "<a href=\"#%s\"%s>%s</a>"
|
|
||||||
(org-export-get-reference destination info)
|
|
||||||
attributes
|
|
||||||
desc))))
|
|
||||||
;; Links pointing to a headline: Find destination and build
|
|
||||||
;; appropriate referencing command.
|
|
||||||
((member type '("custom-id" "fuzzy" "id"))
|
|
||||||
(let ((destination (if (string= type "fuzzy")
|
|
||||||
(org-export-resolve-fuzzy-link link info)
|
|
||||||
(org-export-resolve-id-link link info))))
|
|
||||||
(pcase (org-element-type destination)
|
|
||||||
;; ID link points to an external file.
|
|
||||||
(`plain-text
|
|
||||||
(let ((fragment (concat org-html--id-attr-prefix path))
|
|
||||||
;; Treat links to ".org" files as ".html", if needed.
|
|
||||||
(path (funcall link-org-files-as-html-maybe
|
|
||||||
destination info)))
|
|
||||||
(format "<a href=\"%s#%s\"%s>%s</a>"
|
|
||||||
path fragment attributes (or desc destination))))
|
|
||||||
;; Fuzzy link points nowhere.
|
|
||||||
(`nil
|
|
||||||
(format "<i>%s</i>"
|
|
||||||
(or desc
|
|
||||||
(org-export-data
|
|
||||||
(org-element-property :raw-link link) info))))
|
|
||||||
;; Link points to a headline.
|
|
||||||
(`headline
|
|
||||||
(let ((href (org-html--reference destination info))
|
|
||||||
;; What description to use?
|
|
||||||
(desc
|
|
||||||
;; Case 1: Headline is numbered and LINK has no
|
|
||||||
;; description. Display section number.
|
|
||||||
(if (and (org-export-numbered-headline-p destination info)
|
|
||||||
(not desc))
|
|
||||||
(mapconcat #'number-to-string
|
|
||||||
(org-export-get-headline-number
|
|
||||||
destination info) ".")
|
|
||||||
;; Case 2: Either the headline is un-numbered or
|
|
||||||
;; LINK has a custom description. Display LINK's
|
|
||||||
;; description or headline's title.
|
|
||||||
(or desc
|
|
||||||
(org-export-data
|
|
||||||
(org-element-property :title destination) info)))))
|
|
||||||
(format "<a href=\"#%s\"%s>%s</a>" href attributes desc)))
|
|
||||||
;; Fuzzy link points to a target or an element.
|
|
||||||
(_
|
|
||||||
(if (and destination
|
|
||||||
(memq (plist-get info :with-latex) '(mathjax t))
|
|
||||||
(eq 'latex-environment (org-element-type destination))
|
|
||||||
(eq 'math (org-latex--environment-type destination)))
|
|
||||||
;; Caption and labels are introduced within LaTeX
|
|
||||||
;; environment. Use "ref" or "eqref" macro, depending on user
|
|
||||||
;; preference to refer to those in the document.
|
|
||||||
(format (plist-get info :html-equation-reference-format)
|
|
||||||
(org-html--reference destination info))
|
|
||||||
(let* ((ref (org-html--reference destination info))
|
|
||||||
(org-html-standalone-image-predicate
|
|
||||||
#'org-html--has-caption-p)
|
|
||||||
(counter-predicate
|
|
||||||
(if (eq 'latex-environment (org-element-type destination))
|
|
||||||
#'org-html--math-environment-p
|
|
||||||
#'org-html--has-caption-p))
|
|
||||||
(number
|
|
||||||
(cond
|
|
||||||
(desc nil)
|
|
||||||
((org-html-standalone-image-p destination info)
|
|
||||||
(org-export-get-ordinal
|
|
||||||
(org-element-map destination 'link #'identity info t)
|
|
||||||
info '(link) 'org-html-standalone-image-p))
|
|
||||||
(t (org-export-get-ordinal
|
|
||||||
destination info nil counter-predicate))))
|
|
||||||
(desc
|
|
||||||
(cond (desc)
|
|
||||||
((not number) "No description for this link")
|
|
||||||
((numberp number) (number-to-string number))
|
|
||||||
(t (mapconcat #'number-to-string number ".")))))
|
|
||||||
(format "<a href=\"#%s\"%s>%s</a>" ref attributes desc)))))))
|
|
||||||
;; Coderef: replace link with the reference name or the
|
|
||||||
;; equivalent line number.
|
|
||||||
((string= type "coderef")
|
|
||||||
(let ((fragment (concat "coderef-" (org-html-encode-plain-text path))))
|
|
||||||
(format "<a href=\"#%s\" %s%s>%s</a>"
|
|
||||||
fragment
|
|
||||||
(format "class=\"coderef\" onmouseover=\"CodeHighlightOn(this, \
|
|
||||||
'%s');\" onmouseout=\"CodeHighlightOff(this, '%s');\""
|
|
||||||
fragment fragment)
|
|
||||||
attributes
|
|
||||||
(format (org-export-get-coderef-format path desc)
|
|
||||||
(org-export-resolve-coderef path info)))))
|
|
||||||
;; External link with a description part.
|
|
||||||
((and path desc)
|
|
||||||
(format "<a href=\"%s\"%s>%s</a>"
|
|
||||||
(org-html-encode-plain-text path)
|
|
||||||
attributes
|
|
||||||
desc))
|
|
||||||
;; External link without a description part.
|
|
||||||
(path
|
|
||||||
(let ((path (org-html-encode-plain-text path)))
|
|
||||||
(format "<a href=\"%s\"%s>%s</a>" path attributes path)))
|
|
||||||
;; No path, only description. Try to do something useful.
|
|
||||||
(t
|
|
||||||
(format "<i>%s</i>" desc)))))
|
|
||||||
|
|
||||||
|
|
||||||
;;; End-user functions
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun org-svg4css-export-as-html
|
|
||||||
(&optional async subtreep visible-only body-only ext-plist)
|
|
||||||
"Export current buffer to an HTML buffer.
|
|
||||||
|
|
||||||
If narrowing is active in the current buffer, only export its
|
|
||||||
narrowed part.
|
|
||||||
|
|
||||||
If a region is active, export that region.
|
|
||||||
|
|
||||||
A non-nil optional argument ASYNC means the process should happen
|
|
||||||
asynchronously. The resulting buffer should be accessible
|
|
||||||
through the `org-export-stack' interface.
|
|
||||||
|
|
||||||
When optional argument SUBTREEP is non-nil, export the sub-tree
|
|
||||||
at point, extracting information from the headline properties
|
|
||||||
first.
|
|
||||||
|
|
||||||
When optional argument VISIBLE-ONLY is non-nil, don't export
|
|
||||||
contents of hidden elements.
|
|
||||||
|
|
||||||
When optional argument BODY-ONLY is non-nil, only write code
|
|
||||||
between \"<body>\" and \"</body>\" tags.
|
|
||||||
|
|
||||||
EXT-PLIST, when provided, is a property list with external
|
|
||||||
parameters overriding Org default settings, but still inferior to
|
|
||||||
file-local settings.
|
|
||||||
|
|
||||||
Export is done in a buffer named \"*Org SVG4CSS Export*\", which
|
|
||||||
will be displayed when `org-export-show-temporary-export-buffer'
|
|
||||||
is non-nil."
|
|
||||||
(interactive)
|
|
||||||
(org-export-to-buffer 'svg4css "*Org SVG4CSS Export*"
|
|
||||||
async subtreep visible-only body-only ext-plist
|
|
||||||
(lambda () (set-auto-mode t))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun org-svg4css-export-to-html
|
|
||||||
(&optional async subtreep visible-only body-only ext-plist)
|
|
||||||
"Export current buffer to an HTML file.
|
|
||||||
|
|
||||||
If narrowing is active in the current buffer, only export its
|
|
||||||
narrowed part.
|
|
||||||
|
|
||||||
If a region is active, export that region.
|
|
||||||
|
|
||||||
A non-nil optional argument ASYNC means the process should happen
|
|
||||||
asynchronously. The resulting file should be accessible through
|
|
||||||
the `org-export-stack' interface.
|
|
||||||
|
|
||||||
When optional argument SUBTREEP is non-nil, export the sub-tree
|
|
||||||
at point, extracting information from the headline properties
|
|
||||||
first.
|
|
||||||
|
|
||||||
When optional argument VISIBLE-ONLY is non-nil, don't export
|
|
||||||
contents of hidden elements.
|
|
||||||
|
|
||||||
When optional argument BODY-ONLY is non-nil, only write code
|
|
||||||
between \"<body>\" and \"</body>\" tags.
|
|
||||||
|
|
||||||
EXT-PLIST, when provided, is a property list with external
|
|
||||||
parameters overriding Org default settings, but still inferior to
|
|
||||||
file-local settings.
|
|
||||||
|
|
||||||
Return output file's name."
|
|
||||||
(interactive)
|
|
||||||
(let* ((extension (concat
|
|
||||||
(when (> (length org-html-extension) 0) ".")
|
|
||||||
(or (plist-get ext-plist :html-extension)
|
|
||||||
org-html-extension
|
|
||||||
"html")))
|
|
||||||
(file (org-export-output-file-name extension subtreep))
|
|
||||||
(org-export-coding-system org-html-coding-system))
|
|
||||||
(org-export-to-file 'svg4css file
|
|
||||||
async subtreep visible-only body-only ext-plist)))
|
|
||||||
|
|
||||||
(provide 'ox-svg4css)
|
|
||||||
|
|
||||||
;;; ox-svg4css.el ends here
|
|
Loading…
Reference in New Issue
Block a user