summaryrefslogtreecommitdiff
path: root/contrib/lisp/ox-koma-letter.el
diff options
context:
space:
mode:
authorS├ębastien Delafond <sdelafond@gmail.com>2016-11-07 10:41:54 +0100
committerS├ębastien Delafond <sdelafond@gmail.com>2016-11-07 10:41:54 +0100
commitec84430cf4e09ba25ec675debdf802bc28111e06 (patch)
tree9c64bc8a0cd5e8cac82aa5fdf369d40529f140f8 /contrib/lisp/ox-koma-letter.el
parent84539dca3aa301ecfe48858eceef1ced0505388b (diff)
Imported Upstream version 9.0
Diffstat (limited to 'contrib/lisp/ox-koma-letter.el')
-rw-r--r--contrib/lisp/ox-koma-letter.el264
1 files changed, 155 insertions, 109 deletions
diff --git a/contrib/lisp/ox-koma-letter.el b/contrib/lisp/ox-koma-letter.el
index 48d4ead..801ab7d 100644
--- a/contrib/lisp/ox-koma-letter.el
+++ b/contrib/lisp/ox-koma-letter.el
@@ -41,13 +41,14 @@
;; - PHONE_NUMBER: see `org-koma-letter-phone-number',
;; - SIGNATURE: see `org-koma-letter-signature',
;; - PLACE: see `org-koma-letter-place',
+;; - LOCATION: see `org-koma-letter-location',
;; - TO_ADDRESS: If unspecified this is set to "\mbox{}".
;;
-;; TO_ADDRESS and FROM_ADDRESS can also be specified using heading
-;; with the special tags specified in
-;; `org-koma-letter-special-tags-in-letter', namely "to" and "from".
-;; LaTeX line breaks are not necessary if using these headings. If
-;; both a headline and a keyword specify a to or from address the
+;; TO_ADDRESS, FROM_ADDRESS, LOCATION, CLOSING, and SIGNATURE can also
+;; be specified using "special headings" with the special tags
+;; specified in `org-koma-letter-special-tags-in-letter'. LaTeX line
+;; breaks are not necessary for TO_ADDRESS, FROM_ADDRESS and LOCATION.
+;; If both a headline and a keyword specify a to or from address the
;; value is determined in accordance with
;; `org-koma-letter-prefer-special-headings'.
;;
@@ -58,6 +59,7 @@
;; - phone (see `org-koma-letter-use-phone')
;; - email (see `org-koma-letter-use-email')
;; - place (see `org-koma-letter-use-place')
+;; - location (see `org-koma-letter-use-location')
;; - subject, a list of format options
;; (see `org-koma-letter-subject-format')
;; - after-closing-order, a list of the ordering of headings with
@@ -80,9 +82,9 @@
;; `org-koma-letter-special-tags-after-closing' used as macros and the
;; content of the headline is the argument.
;;
-;; Headlines with two and from may also be used rather than the
-;; keyword approach described above. If both a keyword and a headline
-;; with information is present precedence is determined by
+;; Headlines with to and from may also be used rather than the keyword
+;; approach described above. If both a keyword and a headline with
+;; information is present precedence is determined by
;; `org-koma-letter-prefer-special-headings'.
;;
;; You need an appropriate association in `org-latex-classes' in order
@@ -188,17 +190,35 @@ This option can also be set with the PLACE keyword."
:group 'org-export-koma-letter
:type 'string)
+(defcustom org-koma-letter-location ""
+ "Sender's extension field, as a string.
+
+This option can also be set with the LOCATION keyword.
+Moreover, when:
+ (1) Either `org-koma-letter-prefer-special-headings' is non-nil
+ or there is no LOCATION keyword or the LOCATION keyword is
+ empty;
+ (2) the letter contains a headline with the special
+ tag \"location\";
+then the location will be set as the content of the location
+special heading.
+
+The location field is typically printed right of the address
+field (See Figure 4.9. in the English manual of 2015-10-03)."
+ :group 'org-export-koma-letter
+ :type 'string)
+
(defcustom org-koma-letter-opening ""
"Letter's opening, as a string.
This option can also be set with the OPENING keyword. Moreover,
when:
- (1) this value is the empty string;
- (2) there's no OPENING keyword or it is empty;
- (3) `org-koma-letter-headline-is-opening-maybe' is non-nil;
- (4) the letter contains a headline without a special
+ (1) Either `org-koma-letter-prefer-special-headings' is non-nil
+ or the CLOSING keyword is empty
+ (2) `org-koma-letter-headline-is-opening-maybe' is non-nil;
+ (3) the letter contains a headline without a special
tag (e.g. \"to\" or \"ps\");
-then the opening will be implicitly set as the headline title."
+then the opening will be implicitly set as the untagged headline title."
:group 'org-export-koma-letter
:type 'string)
@@ -206,12 +226,13 @@ then the opening will be implicitly set as the headline title."
"Letter's closing, as a string.
This option can also be set with the CLOSING keyword. Moreover,
when:
- (1) there's no CLOSING keyword or it is empty;
+ (1) Either `org-koma-letter-prefer-special-headings' is non-nil
+ or the CLOSING keyword is empty;
(2) `org-koma-letter-headline-is-opening-maybe' is non-nil;
(3) the letter contains a headline with the special
- tag closing;
+ tag \"closing\";
then the opening will be set as the title of the closing special
-heading."
+heading title."
:group 'org-export-koma-letter
:type 'string)
@@ -219,12 +240,15 @@ heading."
"Signature, as a string.
This option can also be set with the SIGNATURE keyword.
Moreover, when:
- (1) there's no CLOSING keyword or it is empty;
+ (1) Either `org-koma-letter-prefer-special-headings' is non-nil
+ or there is no CLOSING keyword or the CLOSING keyword is empty;
(2) `org-koma-letter-headline-is-opening-maybe' is non-nil;
(3) the letter contains a headline with the special
- tag closing;
+ tag \"closing\";
then the signature will be set as the content of the
-closing special heading."
+closing special heading.
+
+Note if the content is empty the signature will not be set."
:group 'org-export-koma-letter
:type 'string)
@@ -359,9 +383,9 @@ The value must be a member of `org-latex-classes'."
:type 'string)
(defcustom org-koma-letter-headline-is-opening-maybe t
- "Non-nil means a headline may be used as an opening.
-A headline is only used if #+OPENING is not set. See also
-`org-koma-letter-opening'."
+ "Non-nil means a headline may be used as an opening and closing.
+See also `org-koma-letter-opening' and
+`org-koma-letter-closing'."
:group 'org-export-koma-letter
:type 'boolean)
@@ -372,14 +396,17 @@ e.g. \"title-subject:t\"."
:group 'org-export-koma-letter
:type 'boolean)
-(defconst org-koma-letter-special-tags-in-letter '(to from closing)
+(defconst org-koma-letter-special-tags-in-letter '(to from closing location)
"Header tags related to the letter itself.")
-(defconst org-koma-letter-special-tags-after-closing '(ps encl cc)
- "Header tags to be inserted after closing.")
+(defconst org-koma-letter-special-tags-after-closing '(after_closing ps encl cc)
+ "Header tags to be inserted in the letter after closing.")
+
+(defconst org-koma-letter-special-tags-as-macro '(ps encl cc)
+ "Header tags to be inserted as macros")
(defconst org-koma-letter-special-tags-after-letter '(after_letter)
- "Header tags to be inserted after closing.")
+ "Header tags to be inserted after the letter.")
(defvar org-koma-letter-special-contents nil
"Holds special content temporarily.")
@@ -402,20 +429,18 @@ e.g. \"title-subject:t\"."
(:email "EMAIL" nil (org-koma-letter--get-value org-koma-letter-email) t)
(:to-address "TO_ADDRESS" nil nil newline)
(:place "PLACE" nil org-koma-letter-place)
+ (:location "LOCATION" nil org-koma-letter-location)
(:subject "SUBJECT" nil nil parse)
(:opening "OPENING" nil org-koma-letter-opening parse)
(:closing "CLOSING" nil org-koma-letter-closing parse)
(:signature "SIGNATURE" nil org-koma-letter-signature newline)
- (:special-headings nil "special-headings"
- org-koma-letter-prefer-special-headings)
- (:special-tags nil nil (append
- org-koma-letter-special-tags-in-letter
- org-koma-letter-special-tags-after-closing
- org-koma-letter-special-tags-after-letter))
- (:with-after-closing nil "after-closing-order"
- org-koma-letter-special-tags-after-closing)
- (:with-after-letter nil "after-letter-order"
- org-koma-letter-special-tags-after-letter)
+ (:special-headings nil "special-headings" org-koma-letter-prefer-special-headings)
+ (:special-tags-as-macro nil nil org-koma-letter-special-tags-as-macro)
+ (:special-tags-in-letter nil nil org-koma-letter-special-tags-in-letter)
+ (:special-tags-after-closing nil "after-closing-order"
+ org-koma-letter-special-tags-after-closing)
+ (:special-tags-after-letter nil "after-letter-order"
+ org-koma-letter-special-tags-after-letter)
(:with-backaddress nil "backaddress" org-koma-letter-use-backaddress)
(:with-email nil "email" org-koma-letter-use-email)
(:with-foldmarks nil "foldmarks" org-koma-letter-use-foldmarks)
@@ -428,9 +453,11 @@ e.g. \"title-subject:t\"."
;; They are used to prioritize in-buffer settings over "lco"
;; files. See `org-koma-letter-template'.
(:inbuffer-author "AUTHOR" nil 'koma-letter:empty)
+ (:inbuffer-from "FROM" nil 'koma-letter:empty)
(:inbuffer-email "EMAIL" nil 'koma-letter:empty)
(:inbuffer-phone-number "PHONE_NUMBER" nil 'koma-letter:empty)
(:inbuffer-place "PLACE" nil 'koma-letter:empty)
+ (:inbuffer-location "LOCATION" nil 'koma-letter:empty)
(:inbuffer-signature "SIGNATURE" nil 'koma-letter:empty)
(:inbuffer-with-backaddress nil "backaddress" 'koma-letter:empty)
(:inbuffer-with-email nil "email" 'koma-letter:empty)
@@ -438,10 +465,10 @@ e.g. \"title-subject:t\"."
(:inbuffer-with-phone nil "phone" 'koma-letter:empty)
(:inbuffer-with-place nil "place" 'koma-letter:empty))
:translate-alist '((export-block . org-koma-letter-export-block)
- (export-snippet . org-koma-letter-export-snippet)
- (headline . org-koma-letter-headline)
- (keyword . org-koma-letter-keyword)
- (template . org-koma-letter-template))
+ (export-snippet . org-koma-letter-export-snippet)
+ (headline . org-koma-letter-headline)
+ (keyword . org-koma-letter-keyword)
+ (template . org-koma-letter-template))
:menu-entry
'(?k "Export with KOMA Scrlttr2"
((?L "As LaTeX buffer" org-koma-letter-export-as-latex)
@@ -466,8 +493,9 @@ e.g. \"title-subject:t\"."
(defun org-koma-letter--get-tagged-contents (key)
"Get contents from a headline tagged with KEY.
The contents is stored in `org-koma-letter-special-contents'."
- (cdr (assoc-string (org-koma-letter--get-value key)
- org-koma-letter-special-contents)))
+ (let ((value (cdr (assoc-string (org-koma-letter--get-value key)
+ org-koma-letter-special-contents))))
+ (when value (org-string-nw-p (org-trim value)))))
(defun org-koma-letter--get-value (value)
"Turn value into a string whenever possible.
@@ -479,46 +507,31 @@ return a string or nil."
((symbolp value) (symbol-name value))
(t value))))
-(defun org-koma-letter--special-contents-as-macro
- (keywords &optional keep-newlines no-tag)
+(defun org-koma-letter--special-contents-inline (keywords info)
"Process KEYWORDS members of `org-koma-letter-special-contents'.
KEYWORDS is a list of symbols. Return them as a string to be
formatted.
The function is used for inserting content of special headings
-such as PS.
-
-If KEEP-NEWLINES is non-nil leading and trailing newlines are not
-removed. If NO-TAG is non-nil the content in
-`org-koma-letter-special-contents' are not wrapped in a macro
-named whatever the members of KEYWORDS are called."
+such as the one tagged with PS.
+"
(mapconcat
(lambda (keyword)
(let* ((name (org-koma-letter--get-value keyword))
- (value (org-koma-letter--get-tagged-contents name)))
+ (value (org-koma-letter--get-tagged-contents name))
+ (macrop (memq keyword (plist-get info :special-tags-as-macro))))
(cond ((not value) nil)
- (no-tag (if keep-newlines value (org-trim value)))
- (t (format "\\%s{%s}\n"
- name
- (if keep-newlines value (org-trim value)))))))
+ (macrop (format "\\%s{%s}\n" name value))
+ (t value))))
keywords
- ""))
+ "\n"))
-(defun org-koma-letter--determine-to-and-from (info key)
- "Given INFO determine KEY for the letter.
-KEY should be `to' or `from'.
-`ox-koma-letter' allows two ways to specify TO and FROM. If both
-are present return the preferred one as determined by
-`org-koma-letter-prefer-special-headings'."
- (let ((option (org-string-nw-p
- (plist-get info (if (eq key 'to) :to-address :from-address))))
- (headline (org-koma-letter--get-tagged-contents key)))
- (replace-regexp-in-string
- "\n" "\\\\\\\\\n"
- (org-trim
- (if (plist-get info :special-headings) (or headline option "")
- (or option headline ""))))))
+(defun org-koma-letter--add-latex-newlines (string)
+ "Replace regular newlines with LaTeX newlines (i.e. `\\\\')"
+ (let ((str (org-trim string)))
+ (when (org-string-nw-p str)
+ (replace-regexp-in-string "\n" "\\\\\\\\\n" str))))
@@ -576,12 +589,35 @@ appropriate place."
"Non-nil if HEADLINE is a special headline.
INFO is a plist holding contextual information. Return first
special tag headline."
- (let ((special-tags (plist-get info :special-tags)))
+ (let ((special-tags (append
+ (plist-get info :special-tags-in-letter)
+ (plist-get info :special-tags-after-closing)
+ (plist-get info :special-tags-after-letter))))
(catch 'exit
(dolist (tag (org-export-get-tags headline info))
(let ((tag (assoc-string tag special-tags)))
(when tag (throw 'exit tag)))))))
+(defun org-koma-letter--keyword-or-headline (plist-key pred info)
+ "Return the correct version of opening or closing.
+PLIST-KEY should be a key in info, typically :opening
+or :closing. PRED is a predicate run on headline to determine
+which title to use which takes two arguments, a headline element
+and an info plist. INFO is a plist holding contextual
+information. Return the preferred candidate for the exported of
+PLIST-KEY."
+ (let* ((keyword-candidate (plist-get info plist-key))
+ (headline-candidate (when (and (plist-get info :with-headline-opening)
+ (or (plist-get info :special-headings)
+ (not keyword-candidate)))
+ (org-element-map (plist-get info :parse-tree)
+ 'headline
+ (lambda (head)
+ (when (funcall pred head info)
+ (org-element-property :title head)))
+ info t))))
+ (org-export-data (or headline-candidate keyword-candidate "") info)))
+
;;;; Template
(defun org-koma-letter-template (contents info)
@@ -592,8 +628,10 @@ holding export options."
;; 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.
- (org-latex--make-header info)
+ (org-latex--make-preamble info)
;; Settings. They can come from three locations, in increasing
;; order of precedence: global variables, LCO files and in-buffer
;; settings. Thus, we first insert settings coming from global
@@ -604,10 +642,6 @@ holding export options."
(org-split-string (or (plist-get info :lco) "") " ")
"")
(org-koma-letter--build-settings 'buffer info)
- ;; From address.
- (let ((from-address (org-koma-letter--determine-to-and-from info 'from)))
- (when (org-string-nw-p from-address)
- (format "\\setkomavar{fromaddress}{%s}\n" from-address)))
;; Date.
(format "\\date{%s}\n" (org-export-data (org-export-get-date info) info))
;; Hyperref, document start, and subject and title.
@@ -643,40 +677,33 @@ holding export options."
(when title (format "\\setkomavar{title}{%s}\n" title))
(when (or (org-string-nw-p title) (org-string-nw-p subject)) "\n")))
;; Letter start.
- (format "\\begin{letter}{%%\n%s}\n\n"
- (org-koma-letter--determine-to-and-from info 'to))
+ (let ((keyword-val (plist-get info :to-address))
+ (heading-val (org-koma-letter--get-tagged-contents 'to)))
+ (format "\\begin{letter}{%%\n%s}\n\n"
+ (org-koma-letter--add-latex-newlines
+ (or (if (plist-get info :special-headings)
+ (or heading-val keyword-val)
+ (or keyword-val heading-val))
+ "\\\\mbox{}"))))
;; Opening.
(format "\\opening{%s}\n\n"
- (org-export-data
- (or (org-string-nw-p (plist-get info :opening))
- (when (plist-get info :with-headline-opening)
- (org-element-map (plist-get info :parse-tree) 'headline
- (lambda (head)
- (unless (org-koma-letter--special-tag head info)
- (org-element-property :title head)))
- info t))
- "")
+ (org-koma-letter--keyword-or-headline
+ :opening (lambda (h i) (not (org-koma-letter--special-tag h i)))
info))
;; Letter body.
contents
;; Closing.
- (format "\n\\closing{%s}\n"
- (org-export-data
- (or (org-string-nw-p (plist-get info :closing))
- (when (plist-get info :with-headline-opening)
- (org-element-map (plist-get info :parse-tree) 'headline
- (lambda (head)
- (when (eq (org-koma-letter--special-tag head info)
- 'closing)
- (org-element-property :title head)))
- info t)))
+ (format "\\closing{%s}\n"
+ (org-koma-letter--keyword-or-headline
+ :closing (lambda (h i) (eq (org-koma-letter--special-tag h i)
+ 'closing))
info))
- (org-koma-letter--special-contents-as-macro
- (plist-get info :with-after-closing))
+ (org-koma-letter--special-contents-inline
+ (plist-get info :special-tags-after-closing) info)
;; Letter end.
"\n\\end{letter}\n"
- (org-koma-letter--special-contents-as-macro
- (plist-get info :with-after-letter) t t)
+ (org-koma-letter--special-contents-inline
+ (plist-get info :special-tags-after-letter) info)
;; Document end.
"\n\\end{document}"))
@@ -684,14 +711,24 @@ holding export options."
"Build settings string according to type.
SCOPE is either `global' or `buffer'. INFO is a plist used as
a communication channel."
- (let ((check-scope
- (function
- ;; Non-nil value when SETTING was defined in SCOPE.
- (lambda (setting)
- (let ((property (intern (format ":inbuffer-%s" setting))))
- (if (eq scope 'global)
- (eq (plist-get info property) 'koma-letter:empty)
- (not (eq (plist-get info property) 'koma-letter:empty))))))))
+ (let* ((check-scope
+ (function
+ ;; Non-nil value when SETTING was defined in SCOPE.
+ (lambda (setting)
+ (let ((property (intern (format ":inbuffer-%s" setting))))
+ (if (eq scope 'global)
+ (eq (plist-get info property) 'koma-letter:empty)
+ (not (eq (plist-get info property) 'koma-letter:empty)))))))
+ (heading-or-key-value
+ (function
+ (lambda (heading key &optional scoped)
+ (let* ((heading-val
+ (org-koma-letter--get-tagged-contents heading))
+ (key-val (org-string-nw-p (plist-get info key)))
+ (scopedp (funcall check-scope (or scoped heading))))
+ (and (or (and key-val scopedp) heading-val)
+ (not (and (eq scope 'global) heading-val))
+ (if scopedp key-val heading-val)))))))
(concat
;; Name.
(let ((author (plist-get info :author)))
@@ -699,6 +736,11 @@ a communication channel."
(funcall check-scope 'author)
(format "\\setkomavar{fromname}{%s}\n"
(org-export-data author info))))
+ ;; From.
+ (let ((from (funcall heading-or-key-value 'from :from-address)))
+ (and from
+ (format "\\setkomavar{fromaddress}{%s}\n"
+ (org-koma-letter--add-latex-newlines from))))
;; Email.
(let ((email (plist-get info :email)))
(and email
@@ -742,6 +784,10 @@ a communication channel."
(format "\\setkomavar{place}{%s}\n"
(if (plist-get info :with-place) (plist-get info :place)
""))))
+ ;; Location.
+ (let ((location (funcall heading-or-key-value 'location :location)))
+ (and location
+ (format "\\setkomavar{location}{%s}\n" location)))
;; Folding marks.
(and (funcall check-scope 'with-foldmarks)
(let ((foldmarks (plist-get info :with-foldmarks)))