From 0e987ba7777b45e9f758c89cb745525b31b87461 Mon Sep 17 00:00:00 2001 From: Daniel Weschke Date: Tue, 16 Feb 2021 16:10:13 +0100 Subject: [PATCH] start to implement org export of custom article --- README.md | 4 +- README.org | 4 +- lisp/my/my-org-article.el | 357 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 361 insertions(+), 4 deletions(-) create mode 100644 lisp/my/my-org-article.el diff --git a/README.md b/README.md index ca394ca6..9021ef1f 100644 --- a/README.md +++ b/README.md @@ -453,8 +453,8 @@ file. See [Interlocking](https://www.emacswiki.org/info-ref?find=Interlocking) i - when using this in an Org mode buffer: `#+HEADER: :fit yes :imagemagick yes :iminoptions -density 300` - can leads to: - - convert: attempt to perform an operation not allowed by the security policy \`gs’ @ error/delegate.c/ExternalDelegateCommand/378. - - convert: no images defined \`DESYlogotikz.png’ @ error/convert.c/ConvertImageCommand/3282. + - ``convert: attempt to perform an operation not allowed by the security policy `gs' @ error/delegate.c/ExternalDelegateCommand/378.`` + - ``convert: no images defined `DESY_logo_tikz.png' @ error/convert.c/ConvertImageCommand/3282.`` - edit `/etc/ImageMagick-7/policy.xml` and comment out - `` diff --git a/README.org b/README.org index 397fd8f4..1fa61134 100644 --- a/README.org +++ b/README.org @@ -168,8 +168,8 @@ file. See [[https://www.emacswiki.org/info-ref?find=Interlocking][Interlocking]] - when using this in an Org mode buffer: =#+HEADER: :fit yes :imagemagick yes :iminoptions -density 300= - can leads to: - - convert: attempt to perform an operation not allowed by the security policy `gs' @ error/delegate.c/ExternalDelegateCommand/378. - - convert: no images defined `DESY_logo_tikz.png' @ error/convert.c/ConvertImageCommand/3282. + - =convert: attempt to perform an operation not allowed by the security policy `gs' @ error/delegate.c/ExternalDelegateCommand/378.= + - =convert: no images defined `DESY_logo_tikz.png' @ error/convert.c/ConvertImageCommand/3282.= - edit =/etc/ImageMagick-7/policy.xml= and comment out - ~~ diff --git a/lisp/my/my-org-article.el b/lisp/my/my-org-article.el new file mode 100644 index 00000000..674b2c33 --- /dev/null +++ b/lisp/my/my-org-article.el @@ -0,0 +1,357 @@ +;;; my-org-article.el --- Summary -*- lexical-binding: t -*- + +;;; Commentary: + +;; EXAMPLE: +;; # -*- ispell-local-dictionary: "german" -*- + +;;; Code: +(require 'ox-latex) + +;;; Function Declarations +(defvar my-org-article-export-with-toc) +(defvar my-org-article-latex-default-packages-alist) +(defvar my-org-article-latex-packages-alist) +(defvar my-org-article-latex-compiler) +(defvar my-org-article-latex-default-class) +(defvar my-org-article-latex-default-class-options) +(defvar my-org-article-latex-header) +(defvar my-org-article-latex-header-extra) + +(org-export-define-derived-backend 'article-latex 'latex + + :menu-entry + '(?A "Export to LaTeX (Article)" + ((?L "As LaTeX buffer" my-org-article-latex-export-as-latex) + (?l "As LaTeX file" my-org-article-latex-export-to-latex) + (?p "As PDF file" my-org-article-latex-export-to-pdf) + (?o "As PDF file and open" + (lambda (a s v b) + (if a (my-org-article-latex-export-to-pdf t s v b) + (org-open-file (my-org-article-latex-export-to-pdf nil s v b))))))) + :options-alist + '((:with-toc nil "toc" my-org-article-export-with-toc) + (:latex-class "LATEX_CLASS" nil my-org-article-latex-default-class t) + (:latex-class-options "LATEX_CLASS_OPTIONS" nil my-org-article-latex-default-class-options t) + (:latex-header "LATEX_HEADER" nil my-org-article-latex-header newline) + (:latex-header-extra "LATEX_HEADER_EXTRA" nil my-org-article-latex-header-extra newline) + (:latex-compiler "LATEX_COMPILER" nil my-org-article-latex-compiler t)) + + :translate-alist + '((template . my-org-article-latex-template)) + ) + + +;;; User Configurable Variables + +(defgroup my-org-export-article nil + "Options for exporting Org mode files." + :tag "Org Export" + :group 'org) + +(defcustom my-org-article-export-with-toc nil + "See `org-export-with-toc'." + :group 'my-org-export-article + :type '(choice + (const :tag "No Table of Contents" nil) + (const :tag "Full Table of Contents" t) + (integer :tag "TOC to level")) + :safe (lambda (x) + (or (booleanp x) + (integerp x)))) + +;;;; Compilation + +(defcustom my-org-articel-latex-compiler "lualatex" + "See `org-latex-compiler'." + :group 'my-org-export-article + :type '(choice + (const :tag "pdfLaTeX" "pdflatex") + (const :tag "XeLaTeX" "xelatex") + (const :tag "LuaLaTeX" "lualatex") + (const :tag "Unset" "")) + :version "26.1" + :package-version '(Org . "9.0")) + +;;;; Preamble + +(defcustom my-org-article-latex-class "koma-letter" + "The default LaTeX class." + :group 'my-org-export-article + :type '(string :tag "LaTeX class")) + +(defcustom my-org-article-latex-default-class-options "[enlargefirstpage]" + "The default LaTeX class options." + :group 'my-org-export-article + :type '(string :tag "LaTeX class")) + +(add-to-list 'org-latex-classes + '("koma-letter" "\\documentclass{scrlttr2}" + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}") + ("\\paragraph{%s}" . "\\paragraph*{%s}") + ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))) + +(defcustom my-org-article-latex-header + "\\setlength{\\parskip}{6pt} +\\setlength{\\parindent}{0pt} +\\setlength{\\textheight}{22.5cm} + +\\newcommand{\\fromassociation}{<>} +\\newcommand{\\fromname}{<>} +\\setkomavar{fromname}{\\fromname} +\\newcommand{\\fromstreet}{<>} +\\newcommand{\\fromplace}{<>} +\\setkomavar{fromaddress}{\\fromstreet, \\fromplace} +\\setkomavar{fromphone}{<>} +\\setkomavar{fromurl}{<>} +\\setkomavar{fromemail}{<>} +\\setkomavar{place}{<>} +\\newcommand\\toassociation{<>} +\\newcommand\\toname{<>} +\\newcommand\\tostreet{<>} +\\newcommand\\toplace{<>} +\\newcommand\\subject{<>} +\\newcommand\\subjectextra{<>} + +% adjust some spacings +\\makeatletter +\\@setplength{toaddrwidth}{10cm} +\\makeatother +" + "Preamble options." + :group 'my-org-export-article) + +(defcustom my-org-article-latex-header-extra "" + "Preamble extra options." + :group 'my-org-export-article) + +(defcustom my-org-article-latex-default-packages-alist + '(("AUTO" "inputenc" t ("pdflatex")) + ("T1" "fontenc" t ("pdflatex")) + ("" "graphicx" t) + ("" "grffile" t) + ("" "longtable" nil) + ("" "wrapfig" nil) + ("" "rotating" nil) + ("normalem" "ulem" t) + ("" "amsmath" t) + ("" "textcomp" t) + ("" "amssymb" t) + ("" "capt-of" nil) + ("" "hyperref" nil) + ;; + ("ngerman" "babel" nil) + ("utf8" "inputenc" nil) + ("" "scrlayer-scrpage" nil) + ) + "See `org-latex-default-packages-alist'." + :group 'my-org-export-article + ;;:set 'org-set-packages-alist + ;;:get 'org-get-packages-alist + :version "26.1" + :package-version '(Org . "8.3") + :type '(repeat + (choice + (list :tag "options/package pair" + (string :tag "options") + (string :tag "package") + (boolean :tag "Snippet") + (choice + (const :tag "For all compilers" nil) + (repeat :tag "Allowed compiler" string))) + (string :tag "A line of LaTeX")))) + +(defcustom my-org-article-latex-packages-alist nil + "See `org-latex-packages-alist'." + :group 'my-org-export-article + ;;:set 'org-set-packages-alist + ;;:get 'org-get-packages-alist + :type '(repeat + (choice + (list :tag "options/package pair" + (string :tag "options") + (string :tag "package") + (boolean :tag "Snippet")) + (string :tag "A line of LaTeX")))) + +;;;; Document + +(defcustom my-org-letter-latex-opening + "\\firsthead{ + \\begin{flushright}\\textsf{\\begin{tabular}{l} + \\fromassociation \\\\ \\usekomavar{fromname} \\\\ \\fromstreet \\\\ + \\fromplace\\\\[3mm] \\usekomavar{fromphone} \\\\ \\usekomavar{fromemail} + \\end{tabular}}\\end{flushright} +} +% Kopf und Fußzeile der Folgeseiten +\\defpagestyle{nextpage}{{} {} {\\textsf{\\parbox{\\hsize}{\\usekomavar{fromname}\\today\\ \\hrulefill\\ \\pagename~\\thepage}}}} + {{} {} {}} +\\pagestyle{nextpage} + +\\begin{letter}{Empfänger} % den Wert Empfänger nicht verändern +\\setkomavar{toname}{\\toassociation \\\\ \\toname} +\\setkomavar{toaddress}{\\tostreet \\\\ \\toplace} + +\\setkomavar{subject}{\\subject \\\\ {\\normalfont \\subjectextra}} + +\\opening{Sehr geehrter \\toname,}" + "Letter opening." + :group 'my-org-export-article) + +(defcustom my-org-letter-latex-closing + "\\closing{Freundliche Grüße,}" + "Letter closing." + :group 'my-org-export-article) + + +;;; Template + +;;;###autoload +(defun my-org-article-latex-make-preamble (info &optional template snippet?) + "See `org-latex-make-preamble'" + (let* ((class (plist-get info :latex-class)) + (class-template + (or template + (let* ((class-options (plist-get info :latex-class-options)) + (header (nth 1 (assoc class (plist-get info :latex-classes))))) + (and (stringp header) + (if (not class-options) header + (replace-regexp-in-string + "^[ \t]*\\\\documentclass\\(\\(\\[[^]]*\\]\\)?\\)" + class-options header t nil 1)))) + (user-error "Unknown LaTeX class `%s'" class)))) + (org-latex-guess-polyglossia-language + (org-latex-guess-babel-language + (org-latex-guess-inputenc + (org-element-normalize-string + (org-splice-latex-header + class-template + (org-latex--remove-packages my-org-letter-latex-default-packages-alist info) + (org-latex--remove-packages my-org-letter-latex-packages-alist info) + snippet? + (mapconcat #'org-element-normalize-string + (list (s-replace-all + (list (cons "<>" (plist-get info :letter-from-association)) + (cons "<>" (plist-get info :letter-from-name)) + (cons "<>" (plist-get info :letter-from-street)) + (cons "<>" (plist-get info :letter-from-place)) + (cons "<>" (plist-get info :letter-from-phone)) + (cons "<>" (plist-get info :letter-from-url)) + (cons "<>" (plist-get info :letter-from-email)) + (cons "<>" (plist-get info :letter-to-association)) + (cons "<>" (plist-get info :letter-to-name)) + (cons "<>" (plist-get info :letter-to-street)) + (cons "<>" (plist-get info :letter-to-place)) + (cons "<>" (plist-get info :letter-place)) + (cons "<>" (plist-get info :date)) + (cons "<>" (string-replace "\n" "\\\\" (plist-get info :letter-subject))) + (cons "<>" (string-replace "\n" "\\\\" (plist-get info :letter-subject-extra)))) + (plist-get info :latex-header)) + (and (not snippet?) + (plist-get info :latex-header-extra))) + "")))) + info) + info))) + +(defun my-org-article-latex-template (contents info) + "See `org-latex-template'" + (let ((title (org-export-data (plist-get info :title) info)) + (spec (org-latex--format-spec info))) + (concat + ;; Time-stamp. + (and (plist-get info :time-stamp-file) + (format-time-string "%% Created %Y-%m-%d %a %H:%M\n")) + ;; LaTeX compiler. + (org-latex--insert-compiler info) + ;; Document class and packages. + (my-org-letter-latex-make-preamble info) + ;; Possibly limit depth for headline numbering. + (let ((sec-num (plist-get info :section-numbers))) + (when (integerp sec-num) + (format "\\setcounter{secnumdepth}{%d}\n" sec-num))) + ;; Author. + (let ((author (and (plist-get info :with-author) + (let ((auth (plist-get info :author))) + (and auth (org-export-data auth info))))) + (email (and (plist-get info :with-email) + (org-export-data (plist-get info :email) info)))) + (cond ((and author email (not (string= "" email))) + (format "\\author{%s\\thanks{%s}}\n" author email)) + ((or author email) (format "\\author{%s}\n" (or author email))))) + ;; Date. + (let ((date (and (plist-get info :with-date) (org-export-get-date info)))) + (format "\\date{%s}\n" (org-export-data date info))) + ;; Title and subtitle. + (let* ((subtitle (plist-get info :subtitle)) + (formatted-subtitle + (when subtitle + (format (plist-get info :latex-subtitle-format) + (org-export-data subtitle info)))) + (separate (plist-get info :latex-subtitle-separate))) + (concat + (format "\\title{%s%s}\n" title + (if separate "" (or formatted-subtitle ""))) + (when (and separate subtitle) + (concat formatted-subtitle "\n")))) + ;; Hyperref options. + (let ((template (plist-get info :latex-hyperref-template))) + (and (stringp template) + (format-spec template spec))) + ;; Document start. + "\\begin{document}\n\n" + ;; Title command. + (let* ((title-command (plist-get info :latex-title-command)) + (command (and (stringp title-command) + (format-spec title-command spec)))) + (org-element-normalize-string + (cond ((not (plist-get info :with-title)) nil) + ((string= "" title) nil) + ((not (stringp command)) nil) + ((string-match "\\(?:[^%]\\|^\\)%s" command) + (format command title)) + (t command)))) + ;; Table of contents. + (let ((depth (plist-get info :with-toc))) + (when depth + (concat (when (integerp depth) + (format "\\setcounter{tocdepth}{%d}\n" depth)) + (plist-get info :latex-toc-command)))) + ;; Document's body. + (concat (plist-get info :letter-opening) "\n") + contents + (concat (plist-get info :letter-closing) "\n") + ;; attachments + (let ((attachments (plist-get info :letter-attachment))) + (unless (string-equal attachments "") + (concat "\\vspace*{\\fill}\n" + "\\encl{" (string-replace "\n" "\\\\" attachments) "}\n"))) + "\\end{letter}\n" + ;; Creator. + (and (plist-get info :with-creator) + (concat (plist-get info :creator) "\n")) + ;; Document end. + "\\end{document}"))) + +;;;###autoload +(defun my-org-article-latex-export-to-latex + (&optional async subtreep visible-only body-only ext-plist) + "See `org-latex-export-to-latex'" + (interactive) + (let ((outfile (org-export-output-file-name ".tex" subtreep))) + (org-export-to-file 'article-latex outfile + async subtreep visible-only body-only ext-plist))) + +;;;###autoload +(defun my-org-article-latex-export-to-pdf + (&optional async subtreep visible-only body-only ext-plist) + "See `org-latex-export-to-pdf'" + (interactive) + (let ((outfile (org-export-output-file-name ".tex" subtreep))) + (org-export-to-file 'article-latex outfile + async subtreep visible-only body-only ext-plist + (lambda (file) (org-latex-compile file))))) + +(provide 'my-org-article) +;;; my-org-article.el ends here