;;; 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