;;; my-org-letter.el --- Summary -*- lexical-binding: t -*- ;;; Commentary: ;; # -*- ispell-local-dictionary: "german" -*- ;; :FORM: ;; #+LANGUAGE: de ;; #+FROM_ASSOCIATION: XYZ AG ;; #+FROM_NAME: Max Mustermann ;; #+FROM_STREET: Regenbogenstrasse 7 ;; #+FROM_PLACE: 12345 Hamburg ;; #+FROM_PHONE: 0123456789 ;; #+FROM_URL: www.beispiel.de ;; #+FROM_EMAIL: mail@example.de ;; #+TO_ASSOCIATION: Firma AG ;; #+TO_NAME: Herr Karl Marx ;; #+TO_STREET: Firmstrasse 13 ;; #+TO_PLACE: Berlin ;; #+PLACE: Hamburg ;; #+DATE: \today ;; # #+DATE: 3. Januar 2020 ;; :END: ;; #+SUBJECT: Abrechnung ;; #+SUBJECT: 2020 ;; #+SUBJECT_EXTRA: Kontonummer ;; #+SUBJECT_EXTRA: März ;; hiermit sende ich Ihnen die angeforderten Unterlagen zu und ... ;; #+ATTACHMENT: analage 1 ;; #+ATTACHMENT: anlage 2 ;; #+ATTACHMENT: analage 3 ;; #+ATTACHMENT: analage 6 ;;; Code: (require 'ox-latex) ;;; Function Declarations (defvar my-org-letter-export-with-toc) (defvar my-org-letter-latex-default-packages-alist) (defvar my-org-letter-latex-packages-alist) (defvar my-org-letter-latex-compiler) (defvar my-org-letter-latex-default-class) (defvar my-org-letter-latex-default-class-options) (defvar my-org-letter-latex-default-header) (defvar my-org-letter-latex-default-header-extra) (defvar my-org-letter-latex-opening-format) (defvar my-org-letter-latex-opening) (defvar my-org-letter-latex-closing-format) (defvar my-org-letter-latex-closing) (defvar my-org-letter-latex-subject) (defvar my-org-letter-latex-subject-extra) (defvar my-org-letter-latex-from-association) (defvar my-org-letter-latex-from-name) (defvar my-org-letter-latex-from-street) (defvar my-org-letter-latex-from-place) (defvar my-org-letter-latex-from-phone) (defvar my-org-letter-latex-from-url) (defvar my-org-letter-latex-from-email) (defvar my-org-letter-latex-to-association) (defvar my-org-letter-latex-to-name) (defvar my-org-letter-latex-to-street) (defvar my-org-letter-latex-to-place) (defvar my-org-letter-latex-place) (defvar my-org-letter-latex-attachment) (defcustom my-org-letter-export-with-toc nil "") (defcustom my-org-letter-latex-subject "" "") (defcustom my-org-letter-latex-subject-extra "" "") (defcustom my-org-letter-latex-from-association "" "") (defcustom my-org-letter-latex-from-name "" "") (defcustom my-org-letter-latex-from-street "" "") (defcustom my-org-letter-latex-from-place "" "") (defcustom my-org-letter-latex-from-phone "" "") (defcustom my-org-letter-latex-from-url "" "") (defcustom my-org-letter-latex-from-email "" "") (defcustom my-org-letter-latex-to-association "" "") (defcustom my-org-letter-latex-to-name "" "") (defcustom my-org-letter-latex-to-street "" "") (defcustom my-org-letter-latex-to-place "" "") (defcustom my-org-letter-latex-place "" "") (defcustom my-org-letter-latex-attachment "" "") (org-export-define-derived-backend 'letter-latex 'latex :menu-entry '(?l ?l ( ;;(?T "As LaTeX buffer" my-org-letter-latex-export-as-latex) ;;(?t "As LaTeX file" my-org-letter-latex-export-to-latex) (?t "As PDF-letter file" my-org-letter-latex-export-to-pdf) (?T "As PDF-letter file and open" (lambda (a s v b) (if a (my-org-letter-latex-export-to-pdf t s v b) (org-open-file (my-org-letter-latex-export-to-pdf nil s v b))))))) :options-alist '((:with-toc nil "toc" my-org-letter-export-with-toc) (:latex-class "LATEX_CLASS" nil my-org-letter-latex-default-class t) (:latex-class-options "LATEX_CLASS_OPTIONS" nil my-org-letter-latex-default-class-options t) (:latex-header "LATEX_HEADER" nil my-org-letter-latex-default-header newline) (:latex-header-extra "LATEX_HEADER_EXTRA" nil my-org-letter-latex-default-header-extra newline) (:latex-compiler "LATEX_COMPILER" nil my-org-letter-latex-compiler) (:letter-closing-format "CLOSING_FORMAT" nil my-org-letter-latex-closing-format newline) (:letter-closing "CLOSING" nil my-org-letter-latex-closing newline) (:letter-opening-format "OPENING_FORMAT" nil my-org-letter-latex-opening-format newline) (:letter-opening "OPENING" nil my-org-letter-latex-opening newline) (:letter-subject "SUBJECT" nil my-org-letter-latex-subject newline) (:letter-subject-extra "SUBJECT_EXTRA" nil my-org-letter-latex-subject-extra newline) (:letter-from-association "FROM_ASSOCIATION" nil my-org-letter-latex-from-association t) (:letter-from-name "FROM_NAME" nil my-org-letter-latex-from-name t) (:letter-from-street "FROM_STREET" nil my-org-letter-latex-from-street t) (:letter-from-place "FROM_PLACE" nil my-org-letter-latex-from-place t) (:letter-from-phone "FROM_PHONE" nil my-org-letter-latex-from-phone t) (:letter-from-url "FROM_URL" nil my-org-letter-latex-from-url t) (:letter-from-email "FROM_EMAIL" nil my-org-letter-latex-from-email t) (:letter-to-association "TO_ASSOCIATION" nil my-org-letter-latex-to-association t) (:letter-to-name "TO_NAME" nil my-org-letter-latex-to-name t) (:letter-to-street "TO_STREET" nil my-org-letter-latex-to-street t) (:letter-to-place "TO_PLACE" nil my-org-letter-latex-to-place t) (:letter-place "PLACE" nil my-org-letter-latex-place t) (:letter-attachment "ATTACHMENT" nil my-org-letter-latex-attachment newline)) :translate-alist '((template . my-org-letter-latex-template)) ) ;;;; Compilation (defcustom my-org-letter-latex-compiler "lualatex" "See `org-latex-compiler'" :group 'org-export-latex :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-letter-latex-default-class "koma-letter" "The default LaTeX class." :group 'org-export-latex :type '(string :tag "LaTeX class")) (defcustom my-org-letter-latex-default-class-options "[enlargefirstpage]" "The default LaTeX class options." :group 'org-export-latex :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-letter-latex-default-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-letter-latex) (defcustom my-org-letter-latex-default-header-extra "" "Preamble extra options" :group 'my-org-letter-latex ) (defcustom my-org-letter-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-letter-latex ;;: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-letter-latex-packages-alist nil "See `org-latex-packages-alist'" :group 'my-org-letter-latex ;;: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-format "\\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{<>}" "Letter opening structure, will replace <> with `my-org-letter-latex-opening'." :group 'my-org-letter-latex) (defcustom my-org-letter-latex-opening "Sehr geehrter \\toname," "Letter opening, see also `my-org-letter-latex-opening-format'." :group 'my-org-letter-latex) (defcustom my-org-letter-latex-closing-format "\\closing{<>}" "Letter closing structure, will replace <> with `my-org-letter-latex-closing'." :group 'my-org-letter-latex) (defcustom my-org-letter-latex-closing "Freundliche Grüße," "Letter closing, see also `my-org-letter-latex-closing-format'." :group 'my-org-letter-latex) ;;; Template ;;;###autoload (defun my-org-letter-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-letter-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 (string-replace "<>" (plist-get info :letter-opening) (plist-get info :letter-opening-format)) "\n") contents (concat (string-replace "<>" (plist-get info :letter-closing) (plist-get info :letter-closing-format)) "\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-letter-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 'letter-latex outfile async subtreep visible-only body-only ext-plist))) ;;;###autoload (defun my-org-letter-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 'letter-latex outfile async subtreep visible-only body-only ext-plist (lambda (file) (org-latex-compile file))))) (provide 'my-org-letter) ;;; my-org-letter.el ends here