447 lines
16 KiB
EmacsLisp
447 lines
16 KiB
EmacsLisp
;;; 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}{<<fromassociation>>}
|
||
\\newcommand{\\fromname}{<<fromname>>}
|
||
\\setkomavar{fromname}{\\fromname}
|
||
\\newcommand{\\fromstreet}{<<fromstreet>>}
|
||
\\newcommand{\\fromplace}{<<fromplace>>}
|
||
\\setkomavar{fromaddress}{\\fromstreet, \\fromplace}
|
||
\\setkomavar{fromphone}{<<fromphone>>}
|
||
\\setkomavar{fromurl}{<<fromurl>>}
|
||
\\setkomavar{fromemail}{<<fromemail>>}
|
||
\\setkomavar{place}{<<place>>}
|
||
\\newcommand\\toassociation{<<toassociation>>}
|
||
\\newcommand\\toname{<<toname>>}
|
||
\\newcommand\\tostreet{<<tostreet>>}
|
||
\\newcommand\\toplace{<<toplace>>}
|
||
\\newcommand\\subject{<<subject>>}
|
||
\\newcommand\\subjectextra{<<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{<<opening>>}"
|
||
"Letter opening structure, will replace <<opening>> 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{<<closing>>}"
|
||
"Letter closing structure, will replace <<closing>> 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 "<<fromassociation>>" (plist-get info :letter-from-association))
|
||
(cons "<<fromname>>" (plist-get info :letter-from-name))
|
||
(cons "<<fromstreet>>" (plist-get info :letter-from-street))
|
||
(cons "<<fromplace>>" (plist-get info :letter-from-place))
|
||
(cons "<<fromphone>>" (plist-get info :letter-from-phone))
|
||
(cons "<<fromurl>>" (plist-get info :letter-from-url))
|
||
(cons "<<fromemail>>" (plist-get info :letter-from-email))
|
||
(cons "<<toassociation>>" (plist-get info :letter-to-association))
|
||
(cons "<<toname>>" (plist-get info :letter-to-name))
|
||
(cons "<<tostreet>>" (plist-get info :letter-to-street))
|
||
(cons "<<toplace>>" (plist-get info :letter-to-place))
|
||
(cons "<<place>>" (plist-get info :letter-place))
|
||
(cons "<<date>>" (plist-get info :date))
|
||
(cons "<<subject>>" (string-replace "\n" "\\\\" (plist-get info :letter-subject)))
|
||
(cons "<<subjectextra>>" (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
|
||
"<<opening>>"
|
||
(plist-get info :letter-opening)
|
||
(plist-get info :letter-opening-format))
|
||
"\n")
|
||
contents
|
||
(concat (string-replace
|
||
"<<closing>>"
|
||
(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
|