diff --git a/lisp/my/my-org-letter.el b/lisp/my/my-org-letter.el new file mode 100644 index 00000000..61c34022 --- /dev/null +++ b/lisp/my/my-org-letter.el @@ -0,0 +1,422 @@ +;;; 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) +(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 "Export to LaTeX (Letter)" + ((?L "As LaTeX buffer" my-org-letter-latex-export-as-latex) + (?l "As LaTeX file" my-org-letter-latex-export-to-latex) + (?p "As PDF file" my-org-letter-latex-export-to-pdf) + (?o "As PDF 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 "CLOSING" nil my-org-letter-latex-closing 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 + "\\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-letter-latex) + +(defcustom my-org-letter-latex-closing + "\\closing{Freundliche Grüße,}" + "Letter closing." + :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 (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-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 diff --git a/settings/my-settings.el b/settings/my-settings.el index cc58ce4d..5bf8ccf5 100644 --- a/settings/my-settings.el +++ b/settings/my-settings.el @@ -8,5 +8,9 @@ (add-hook 'org-mode-hook 'my-org-link-color-hook) (add-hook 'org-ctrl-c-ctrl-c-hook 'my-org-table-cell-color-attr))) +(use-package my-org-letter + :load-path "lisp/my" + :after (org)) + (provide 'my-settings) ;;; my-settings.el ends here