ox-koma-letter.el (40392B)
1 ;;; ox-koma-letter.el --- KOMA Scrlttr2 Back-End for Org Export Engine -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2007-2023 Free Software Foundation, Inc. 4 5 ;; Author: Nicolas Goaziou <n.goaziou AT gmail DOT com> 6 ;; Alan Schmitt <alan.schmitt AT polytechnique DOT org> 7 ;; Viktor Rosenfeld <listuser36 AT gmail DOT com> 8 ;; Rasmus Pank Roulund <emacs AT pank DOT eu> 9 ;; Maintainer: Marco Wahl <marcowahlsoft@gmail.com> 10 ;; Keywords: org, wp, tex 11 12 ;; This file is part of GNU Emacs. 13 14 ;; GNU Emacs is free software: you can redistribute it and/or modify 15 ;; it under the terms of the GNU General Public License as published by 16 ;; the Free Software Foundation, either version 3 of the License, or 17 ;; (at your option) any later version. 18 19 ;; GNU Emacs is distributed in the hope that it will be useful, 20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 ;; GNU General Public License for more details. 23 24 ;; You should have received a copy of the GNU General Public License 25 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. 26 27 ;;; Commentary: 28 ;; 29 ;; This library implements a KOMA Scrlttr2 back-end, derived from the 30 ;; LaTeX one. 31 ;; 32 ;; Depending on the desired output format, three commands are provided 33 ;; for export: `org-koma-letter-export-as-latex' (temporary buffer), 34 ;; `org-koma-letter-export-to-latex' ("tex" file) and 35 ;; `org-koma-letter-export-to-pdf' ("pdf" file). 36 ;; 37 ;; On top of buffer keywords supported by `latex' back-end (see 38 ;; `org-latex-packages-alist'), this back-end introduces the following 39 ;; keywords: 40 ;; - CLOSING: see `org-koma-letter-closing', 41 ;; - FROM_ADDRESS: see `org-koma-letter-from-address', 42 ;; - LCO: see `org-koma-letter-class-option-file', 43 ;; - OPENING: see `org-koma-letter-opening', 44 ;; - PHONE_NUMBER: see `org-koma-letter-phone-number', 45 ;; - URL: see `org-koma-letter-url', 46 ;; - FROM_LOGO: see `org-koma-letter-from-logo', 47 ;; - SIGNATURE: see `org-koma-letter-signature', 48 ;; - PLACE: see `org-koma-letter-place', 49 ;; - LOCATION: see `org-koma-letter-location', 50 ;; - TO_ADDRESS: If unspecified this is set to "\mbox{}". 51 ;; 52 ;; TO_ADDRESS, FROM_ADDRESS, LOCATION, CLOSING, and SIGNATURE can also 53 ;; be specified using "special headings" with the special tags 54 ;; specified in `org-koma-letter-special-tags-in-letter'. LaTeX line 55 ;; breaks are not necessary for TO_ADDRESS, FROM_ADDRESS and LOCATION. 56 ;; If both a headline and a keyword specify a to or from address the 57 ;; value is determined in accordance with 58 ;; `org-koma-letter-prefer-special-headings'. 59 ;; 60 ;; A number of OPTIONS settings can be set to change which contents is 61 ;; exported. 62 ;; - backaddress (see `org-koma-letter-use-backaddress') 63 ;; - foldmarks (see `org-koma-letter-use-foldmarks') 64 ;; - phone (see `org-koma-letter-use-phone') 65 ;; - url (see `org-koma-letter-use-url') 66 ;; - from-logo (see `org-koma-letter-use-from-logo') 67 ;; - email (see `org-koma-letter-use-email') 68 ;; - place (see `org-koma-letter-use-place') 69 ;; - location (see `org-koma-letter-location') 70 ;; - subject, a list of format options 71 ;; (see `org-koma-letter-subject-format') 72 ;; - after-closing-order, a list of the ordering of headings with 73 ;; special tags after closing (see 74 ;; `org-koma-letter-special-tags-after-closing') 75 ;; - after-letter-order, as above, but after the end of the letter 76 ;; (see `org-koma-letter-special-tags-after-letter'). 77 ;; 78 ;; The following variables works differently from the main LaTeX class 79 ;; - AUTHOR: Default to user-full-name but may be disabled. 80 ;; (See also `org-koma-letter-author'.) 81 ;; - EMAIL: Same as AUTHOR. (See also `org-koma-letter-email'.) 82 ;; 83 ;; FROM_LOGO uses LaTeX markup. FROM_LOGO provides the 84 ;; "includegraphics" command to tell LaTeX where to find the logo. 85 ;; This command needs to know the logo's directory and file name. The 86 ;; directory can either be relative or absolute, just as you would 87 ;; expect. LaTeX can use three file types for the logo: PDF, JPEG, or 88 ;; PNG. The logo can either include or exclude its extension, which 89 ;; might surprise you. When you exclude its extension, LaTeX will 90 ;; search the directory for the "best" quality graphics format. For 91 ;; example if it finds both logo.pdf and logo.png then it will 92 ;; identify the PDF as "better", and include "logo.pdf". This can be 93 ;; useful, for example, when you are mocking up a logo in the PNG 94 ;; raster format and then switch over to the higher quality PDF vector 95 ;; format. When you include the file extension then LaTeX will 96 ;; include it without searching for higher quality file types. 97 ;; Whatever file type you choose, it will probably require a few 98 ;; design iterations to get the best looking logo size for your 99 ;; letter. Finally, the directory and file name are specified 100 ;; *without* quotes. Here are some examples with commentary, in the 101 ;; location of your letter, with a logo named "logo", to get you 102 ;; started: 103 ;; 104 ;; Logo in the same directory: \includegraphics{logo} 105 ;; or a sub-directory: \includegraphics{logos/production/logo} 106 ;; 107 ;; Logos specified using absolute paths on Linux or Windows: 108 ;; 109 ;; \includegraphics{~/correspondence/logo} 110 ;; \includegraphics{~/correspondence/logos/production/logo} 111 ;; \includegraphics{c:/you/correspondence/logo} 112 ;; \includegraphics{c:/you/correspondence/logos/production/logo} 113 ;; 114 ;; Logos in the same directory where the "better" quality PDF will 115 ;; be chosen over the JPG: 116 ;; 117 ;; \includegraphics{logo.pdf} 118 ;; \includegraphics{logo.png} 119 ;; 120 ;; Headlines are in general ignored. However, headlines with special 121 ;; tags can be used for specified contents like postscript (ps), 122 ;; carbon copy (cc), enclosures (encl) and code to be inserted after 123 ;; \end{letter} (after_letter). Specials tags are defined in 124 ;; `org-koma-letter-special-tags-after-closing' and 125 ;; `org-koma-letter-special-tags-after-letter'. Currently members of 126 ;; `org-koma-letter-special-tags-after-closing' used as macros and the 127 ;; content of the headline is the argument. 128 ;; 129 ;; Headlines with to and from may also be used rather than the keyword 130 ;; approach described above. If both a keyword and a headline with 131 ;; information is present precedence is determined by 132 ;; `org-koma-letter-prefer-special-headings'. 133 ;; 134 ;; You need an appropriate association in `org-latex-classes' in order 135 ;; to use the KOMA Scrlttr2 class. By default, a sparse scrlttr2 136 ;; class is provided: "default-koma-letter". You can also add you own 137 ;; letter class. For instance: 138 ;; 139 ;; (add-to-list 'org-latex-classes 140 ;; '("my-letter" 141 ;; "\\documentclass\[% 142 ;; DIV=14, 143 ;; fontsize=12pt, 144 ;; parskip=half, 145 ;; subject=titled, 146 ;; backaddress=false, 147 ;; fromalign=left, 148 ;; fromemail=true, 149 ;; fromphone=true\]\{scrlttr2\} 150 ;; \[DEFAULT-PACKAGES] 151 ;; \[PACKAGES] 152 ;; \[EXTRA]")) 153 ;; 154 ;; Then, in your Org document, be sure to require the proper class 155 ;; with: 156 ;; 157 ;; #+LATEX_CLASS: my-letter 158 ;; 159 ;; Or by setting `org-koma-letter-default-class'. 160 ;; 161 ;; You may have to load (LaTeX) Babel as well, e.g., by adding 162 ;; it to `org-latex-packages-alist', 163 ;; 164 ;; (add-to-list 'org-latex-packages-alist '("AUTO" "babel" nil)) 165 166 ;;; Code: 167 168 (require 'org-macs) 169 (org-assert-version) 170 171 (require 'cl-lib) 172 (require 'ox-latex) 173 174 ;; Install a default letter class. 175 (unless (assoc "default-koma-letter" org-latex-classes) 176 (add-to-list 'org-latex-classes 177 '("default-koma-letter" "\\documentclass[11pt]{scrlttr2}"))) 178 179 180 ;;; User-Configurable Variables 181 182 (defgroup org-export-koma-letter nil 183 "Options for exporting to KOMA scrlttr2 class in LaTeX export." 184 :tag "Org Koma-Letter" 185 :group 'org-export) 186 187 (defcustom org-koma-letter-class-option-file "NF" 188 "Letter Class Option File. 189 This option can also be set with the LCO keyword." 190 :type 'string) 191 192 (defcustom org-koma-letter-author 'user-full-name 193 "Sender's name. 194 195 This variable defaults to calling the function `user-full-name' 196 which just returns the current function `user-full-name'. 197 Alternatively a string, nil or a function may be given. 198 Functions must return a string. 199 200 This option can also be set with the AUTHOR keyword." 201 :type '(radio (function-item user-full-name) 202 (string) 203 (function) 204 (const :tag "Do not export author" nil))) 205 206 (defcustom org-koma-letter-email 'org-koma-letter-email 207 "Sender's email address. 208 209 This variable defaults to the value `org-koma-letter-email' which 210 returns `user-mail-address'. Alternatively a string, nil or 211 a function may be given. Functions must return a string. 212 213 This option can also be set with the EMAIL keyword." 214 :type '(radio (function-item org-koma-letter-email) 215 (string) 216 (function) 217 (const :tag "Do not export email" nil))) 218 219 (defcustom org-koma-letter-from-address "" 220 "Sender's address, as a string. 221 This option can also be set with one or more FROM_ADDRESS 222 keywords." 223 :type 'string) 224 225 (defcustom org-koma-letter-phone-number "" 226 "Sender's phone number, as a string. 227 This option can also be set with the PHONE_NUMBER keyword." 228 :type 'string) 229 230 (defcustom org-koma-letter-url "" 231 "Sender's URL, e. g., the URL of her homepage. 232 This option can also be set with the URL keyword." 233 :type 'string 234 :safe #'stringp) 235 236 (defcustom org-koma-letter-from-logo "" 237 "Commands for inserting the sender's logo, e. g., \\includegraphics{logo}. 238 This option can also be set with the FROM_LOGO keyword." 239 :type 'string 240 :safe #'stringp) 241 242 (defcustom org-koma-letter-place "" 243 "Place from which the letter is sent, as a string. 244 This option can also be set with the PLACE keyword." 245 :type 'string) 246 247 (defcustom org-koma-letter-location "" 248 "Sender's extension field, as a string. 249 250 This option can also be set with the LOCATION keyword. 251 Moreover, when: 252 (1) Either `org-koma-letter-prefer-special-headings' is non-nil 253 or there is no LOCATION keyword or the LOCATION keyword is 254 empty; 255 (2) the letter contains a headline with the special 256 tag \"location\"; 257 then the location will be set as the content of the location 258 special heading. 259 260 The location field is typically printed right of the address 261 field (See Figure 4.9. in the English manual of 2015-10-03)." 262 :type 'string) 263 264 (defcustom org-koma-letter-opening "" 265 "Letter's opening, as a string. 266 267 This option can also be set with the OPENING keyword. Moreover, 268 when: 269 (1) Either `org-koma-letter-prefer-special-headings' is non-nil 270 or the CLOSING keyword is empty 271 (2) `org-koma-letter-headline-is-opening-maybe' is non-nil; 272 (3) the letter contains a headline without a special 273 tag (e.g. \"to\" or \"ps\"); 274 then the opening will be implicitly set as the untagged headline title." 275 :type 'string) 276 277 (defcustom org-koma-letter-closing "" 278 "Letter's closing, as a string. 279 This option can also be set with the CLOSING keyword. Moreover, 280 when: 281 (1) Either `org-koma-letter-prefer-special-headings' is non-nil 282 or the CLOSING keyword is empty; 283 (2) `org-koma-letter-headline-is-opening-maybe' is non-nil; 284 (3) the letter contains a headline with the special 285 tag \"closing\"; 286 then the opening will be set as the title of the closing special 287 heading title." 288 :type 'string) 289 290 (defcustom org-koma-letter-signature "" 291 "Signature, as a string. 292 This option can also be set with the SIGNATURE keyword. 293 Moreover, when: 294 (1) Either `org-koma-letter-prefer-special-headings' is non-nil 295 or there is no CLOSING keyword or the CLOSING keyword is empty; 296 (2) `org-koma-letter-headline-is-opening-maybe' is non-nil; 297 (3) the letter contains a headline with the special 298 tag \"closing\"; 299 then the signature will be set as the content of the 300 closing special heading. 301 302 Note if the content is empty the signature will not be set." 303 :type 'string) 304 305 (defcustom org-koma-letter-prefer-special-headings nil 306 "Non-nil means prefer headlines over keywords for TO and FROM. 307 This option can also be set with the OPTIONS keyword, e.g.: 308 \"special-headings:t\"." 309 :type 'boolean) 310 311 (defcustom org-koma-letter-subject-format t 312 "Non-nil means include the subject. 313 314 Support formatting options. 315 316 When t, insert a subject using default options. When nil, do not 317 insert a subject at all. It can also be a list of symbols among 318 the following ones: 319 320 `afteropening' Subject after opening 321 `beforeopening' Subject before opening 322 `centered' Subject centered 323 `left' Subject left-justified 324 `right' Subject right-justified 325 `titled' Add title/description to subject 326 `underlined' Set subject underlined 327 `untitled' Do not add title/description to subject 328 329 Please refer to the KOMA-script manual (Table 4.16. in the 330 English manual of 2012-07-22). 331 332 This option can also be set with the OPTIONS keyword, e.g.: 333 \"subject:(underlined centered)\"." 334 :type 335 '(choice 336 (const :tag "No export" nil) 337 (const :tag "Default options" t) 338 (set :tag "Configure options" 339 (const :tag "Subject after opening" afteropening) 340 (const :tag "Subject before opening" beforeopening) 341 (const :tag "Subject centered" centered) 342 (const :tag "Subject left-justified" left) 343 (const :tag "Subject right-justified" right) 344 (const :tag "Add title or description to subject" underlined) 345 (const :tag "Set subject underlined" titled) 346 (const :tag "Do not add title or description to subject" untitled)))) 347 348 (defcustom org-koma-letter-use-backaddress nil 349 "Non-nil prints return address in line above to address. 350 This option can also be set with the OPTIONS keyword, e.g.: 351 \"backaddress:t\"." 352 :type 'boolean) 353 354 (defcustom org-koma-letter-use-foldmarks t 355 "Configure appearance of folding marks. 356 357 When t, activate default folding marks. When nil, do not insert 358 folding marks at all. It can also be a list of symbols among the 359 following ones: 360 361 `B' Activate upper horizontal mark on left paper edge 362 `b' Deactivate upper horizontal mark on left paper edge 363 364 `H' Activate all horizontal marks on left paper edge 365 `h' Deactivate all horizontal marks on left paper edge 366 367 `L' Activate left vertical mark on upper paper edge 368 `l' Deactivate left vertical mark on upper paper edge 369 370 `M' Activate middle horizontal mark on left paper edge 371 `m' Deactivate middle horizontal mark on left paper edge 372 373 `P' Activate punch or center mark on left paper edge 374 `p' Deactivate punch or center mark on left paper edge 375 376 `T' Activate lower horizontal mark on left paper edge 377 `t' Deactivate lower horizontal mark on left paper edge 378 379 `V' Activate all vertical marks on upper paper edge 380 `v' Deactivate all vertical marks on upper paper edge 381 382 This option can also be set with the OPTIONS keyword, e.g.: 383 \"foldmarks:(b l m t)\"." 384 :type '(choice 385 (const :tag "Activate default folding marks" t) 386 (const :tag "Deactivate folding marks" nil) 387 (set 388 :tag "Configure folding marks" 389 (const :tag "Activate upper horizontal mark on left paper edge" B) 390 (const :tag "Deactivate upper horizontal mark on left paper edge" b) 391 (const :tag "Activate all horizontal marks on left paper edge" H) 392 (const :tag "Deactivate all horizontal marks on left paper edge" h) 393 (const :tag "Activate left vertical mark on upper paper edge" L) 394 (const :tag "Deactivate left vertical mark on upper paper edge" l) 395 (const :tag "Activate middle horizontal mark on left paper edge" M) 396 (const :tag "Deactivate middle horizontal mark on left paper edge" m) 397 (const :tag "Activate punch or center mark on left paper edge" P) 398 (const :tag "Deactivate punch or center mark on left paper edge" p) 399 (const :tag "Activate lower horizontal mark on left paper edge" T) 400 (const :tag "Deactivate lower horizontal mark on left paper edge" t) 401 (const :tag "Activate all vertical marks on upper paper edge" V) 402 (const :tag "Deactivate all vertical marks on upper paper edge" v)))) 403 404 (defcustom org-koma-letter-use-phone nil 405 "Non-nil prints sender's phone number. 406 This option can also be set with the OPTIONS keyword, e.g.: 407 \"phone:t\"." 408 :type 'boolean) 409 410 (defcustom org-koma-letter-use-url nil 411 "Non-nil prints sender's URL. 412 This option can also be set with the OPTIONS keyword, e.g.: 413 \"url:t\"." 414 :type 'boolean 415 :safe #'booleanp) 416 417 (defcustom org-koma-letter-use-from-logo nil 418 "Non-nil prints sender's FROM_LOGO. 419 This option can also be set with the OPTIONS keyword, e.g.: 420 \"from-logo:t\"." 421 :type 'boolean 422 :safe #'booleanp) 423 424 (defcustom org-koma-letter-use-email nil 425 "Non-nil prints sender's email address. 426 This option can also be set with the OPTIONS keyword, e.g.: 427 \"email:t\"." 428 :type 'boolean) 429 430 (defcustom org-koma-letter-use-place t 431 "Non-nil prints the letter's place next to the date. 432 This option can also be set with the OPTIONS keyword, e.g.: 433 \"place:nil\"." 434 :type 'boolean) 435 436 (defcustom org-koma-letter-default-class "default-koma-letter" 437 "Default class for `org-koma-letter'. 438 The value must be a member of `org-latex-classes'." 439 :type 'string) 440 441 (defcustom org-koma-letter-headline-is-opening-maybe t 442 "Non-nil means a headline may be used as an opening and closing. 443 See also `org-koma-letter-opening' and 444 `org-koma-letter-closing'." 445 :type 'boolean) 446 447 (defcustom org-koma-letter-prefer-subject nil 448 "Non-nil means title should be interpreted as subject if subject is missing. 449 This option can also be set with the OPTIONS keyword, 450 e.g. \"title-subject:t\"." 451 :type 'boolean) 452 453 (defconst org-koma-letter-special-tags-in-letter '(to from closing location) 454 "Header tags related to the letter itself.") 455 456 (defconst org-koma-letter-special-tags-after-closing '(after_closing ps encl cc) 457 "Header tags to be inserted in the letter after closing.") 458 459 (defconst org-koma-letter-special-tags-as-macro '(ps encl cc) 460 "Header tags to be inserted as macros.") 461 462 (defconst org-koma-letter-special-tags-after-letter '(after_letter) 463 "Header tags to be inserted after the letter.") 464 465 (defvar org-koma-letter-special-contents nil 466 "Holds special content temporarily.") 467 468 469 ;;; Define Back-End 470 471 (org-export-define-derived-backend 'koma-letter 'latex 472 :options-alist 473 '((:latex-class "LATEX_CLASS" nil org-koma-letter-default-class t) 474 (:lco "LCO" nil org-koma-letter-class-option-file) 475 (:author "AUTHOR" nil (org-koma-letter--get-value org-koma-letter-author) parse) 476 (:author-changed-in-buffer-p "AUTHOR" nil nil t) 477 (:from-address "FROM_ADDRESS" nil org-koma-letter-from-address newline) 478 (:phone-number "PHONE_NUMBER" nil org-koma-letter-phone-number) 479 (:url "URL" nil org-koma-letter-url) 480 (:from-logo "FROM_LOGO" nil org-koma-letter-from-logo) 481 (:email "EMAIL" nil (org-koma-letter--get-value org-koma-letter-email) t) 482 (:to-address "TO_ADDRESS" nil nil newline) 483 (:place "PLACE" nil org-koma-letter-place) 484 (:location "LOCATION" nil org-koma-letter-location) 485 (:subject "SUBJECT" nil nil parse) 486 (:opening "OPENING" nil org-koma-letter-opening parse) 487 (:closing "CLOSING" nil org-koma-letter-closing parse) 488 (:signature "SIGNATURE" nil org-koma-letter-signature newline) 489 (:special-headings nil "special-headings" org-koma-letter-prefer-special-headings) 490 (:special-tags-as-macro nil nil org-koma-letter-special-tags-as-macro) 491 (:special-tags-in-letter nil nil org-koma-letter-special-tags-in-letter) 492 (:special-tags-after-closing nil "after-closing-order" 493 org-koma-letter-special-tags-after-closing) 494 (:special-tags-after-letter nil "after-letter-order" 495 org-koma-letter-special-tags-after-letter) 496 (:with-backaddress nil "backaddress" org-koma-letter-use-backaddress) 497 (:with-email nil "email" org-koma-letter-use-email) 498 (:with-foldmarks nil "foldmarks" org-koma-letter-use-foldmarks) 499 (:with-phone nil "phone" org-koma-letter-use-phone) 500 (:with-url nil "url" org-koma-letter-use-url) 501 (:with-from-logo nil "from-logo" org-koma-letter-use-from-logo) 502 (:with-place nil "place" org-koma-letter-use-place) 503 (:with-subject nil "subject" org-koma-letter-subject-format) 504 (:with-title-as-subject nil "title-subject" org-koma-letter-prefer-subject) 505 (:with-headline-opening nil nil org-koma-letter-headline-is-opening-maybe) 506 ;; Special properties non-nil when a setting happened in buffer. 507 ;; They are used to prioritize in-buffer settings over "lco" 508 ;; files. See `org-koma-letter-template'. 509 (:inbuffer-author "AUTHOR" nil 'koma-letter:empty) 510 (:inbuffer-from "FROM" nil 'koma-letter:empty) 511 (:inbuffer-email "EMAIL" nil 'koma-letter:empty) 512 (:inbuffer-phone-number "PHONE_NUMBER" nil 'koma-letter:empty) 513 (:inbuffer-url "URL" nil 'koma-letter:empty) 514 (:inbuffer-from-logo "FROM_LOGO" nil 'koma-letter:empty) 515 (:inbuffer-place "PLACE" nil 'koma-letter:empty) 516 (:inbuffer-location "LOCATION" nil 'koma-letter:empty) 517 (:inbuffer-signature "SIGNATURE" nil 'koma-letter:empty) 518 (:inbuffer-with-backaddress nil "backaddress" 'koma-letter:empty) 519 (:inbuffer-with-email nil "email" 'koma-letter:empty) 520 (:inbuffer-with-foldmarks nil "foldmarks" 'koma-letter:empty) 521 (:inbuffer-with-phone nil "phone" 'koma-letter:empty) 522 (:inbuffer-with-url nil "url" 'koma-letter:empty) 523 (:inbuffer-with-from-logo nil "from-logo" 'koma-letter:empty) 524 (:inbuffer-with-place nil "place" 'koma-letter:empty)) 525 :translate-alist '((export-block . org-koma-letter-export-block) 526 (export-snippet . org-koma-letter-export-snippet) 527 (headline . org-koma-letter-headline) 528 (keyword . org-koma-letter-keyword) 529 (template . org-koma-letter-template)) 530 :menu-entry 531 '(?k "Export with KOMA Scrlttr2" 532 ((?L "As LaTeX buffer" org-koma-letter-export-as-latex) 533 (?l "As LaTeX file" org-koma-letter-export-to-latex) 534 (?p "As PDF file" org-koma-letter-export-to-pdf) 535 (?o "As PDF file and open" 536 (lambda (a s v b) 537 (if a (org-koma-letter-export-to-pdf t s v b) 538 (org-open-file (org-koma-letter-export-to-pdf nil s v b)))))))) 539 540 541 542 ;;; Helper functions 543 544 (defun org-koma-letter-email () 545 "Return the current `user-mail-address'." 546 user-mail-address) 547 548 ;; The following is taken from/inspired by ox-grof.el 549 ;; Thanks, Luis! 550 551 (defun org-koma-letter--get-tagged-contents (key) 552 "Get contents from a headline tagged with KEY. 553 The contents is stored in `org-koma-letter-special-contents'." 554 (let ((value (cdr (assoc-string (org-koma-letter--get-value key) 555 org-koma-letter-special-contents)))) 556 (when value (org-string-nw-p (org-trim value))))) 557 558 (defun org-koma-letter--get-value (value) 559 "Turn value into a string whenever possible. 560 Determines if VALUE is nil, a string, a function or a symbol and 561 return a string or nil." 562 (when value 563 (cond ((stringp value) value) 564 ((functionp value) (funcall value)) 565 ((symbolp value) (symbol-name value)) 566 (t value)))) 567 568 (defun org-koma-letter--special-contents-inline (keywords info) 569 "Process KEYWORDS members of `org-koma-letter-special-contents'. 570 571 KEYWORDS is a list of symbols. Return them as a string to be 572 formatted. 573 574 The function is used for inserting content of special headings 575 such as the one tagged with PS." 576 (mapconcat 577 (lambda (keyword) 578 (let* ((name (org-koma-letter--get-value keyword)) 579 (value (org-koma-letter--get-tagged-contents name)) 580 (macrop (memq keyword (plist-get info :special-tags-as-macro)))) 581 (cond ((not value) nil) 582 (macrop (format "\\%s{%s}\n" name value)) 583 (t value)))) 584 keywords 585 "\n")) 586 587 588 (defun org-koma-letter--add-latex-newlines (string) 589 "Replace regular newlines with LaTeX newlines (i.e. `\\\\')." 590 (let ((str (org-trim string))) 591 (when (org-string-nw-p str) 592 (replace-regexp-in-string "\n" "\\\\\\\\\n" str)))) 593 594 595 596 ;;; Transcode Functions 597 598 ;;;; Export Block 599 600 (defun org-koma-letter-export-block (export-block _contents _info) 601 "Transcode an EXPORT-BLOCK element into KOMA Scrlttr2 code. 602 CONTENTS is nil. INFO is a plist used as a communication 603 channel." 604 (when (member (org-element-property :type export-block) 605 '("KOMA-LETTER" "LATEX")) 606 (org-remove-indentation (org-element-property :value export-block)))) 607 608 ;;;; Export Snippet 609 610 (defun org-koma-letter-export-snippet (export-snippet _contents _info) 611 "Transcode an EXPORT-SNIPPET object into KOMA Scrlttr2 code. 612 CONTENTS is nil. INFO is a plist used as a communication 613 channel." 614 (when (memq (org-export-snippet-backend export-snippet) '(latex koma-letter)) 615 (org-element-property :value export-snippet))) 616 617 ;;;; Keyword 618 619 (defun org-koma-letter-keyword (keyword contents info) 620 "Transcode a KEYWORD element into KOMA Scrlttr2 code. 621 CONTENTS is nil. INFO is a plist used as a communication 622 channel." 623 (let ((key (org-element-property :key keyword)) 624 (value (org-element-property :value keyword))) 625 ;; Handle specifically KOMA-LETTER keywords. Otherwise, fallback 626 ;; to `latex' back-end. 627 (if (equal key "KOMA-LETTER") value 628 (org-export-with-backend 'latex keyword contents info)))) 629 630 ;; Headline 631 632 (defun org-koma-letter-headline (headline contents info) 633 "Transcode a HEADLINE element from Org to LaTeX. 634 CONTENTS holds the contents of the headline. INFO is a plist 635 holding contextual information. 636 637 Note that if a headline is tagged with a tag from 638 `org-koma-letter-special-tags' it will not be exported, but 639 stored in `org-koma-letter-special-contents' and included at the 640 appropriate place." 641 (let ((special-tag (org-koma-letter--special-tag headline info))) 642 (if (not special-tag) 643 contents 644 (push (cons special-tag contents) org-koma-letter-special-contents) 645 ""))) 646 647 (defun org-koma-letter--special-tag (headline info) 648 "Non-nil if HEADLINE is a special headline. 649 INFO is a plist holding contextual information. Return first 650 special tag headline." 651 (let ((special-tags (append 652 (plist-get info :special-tags-in-letter) 653 (plist-get info :special-tags-after-closing) 654 (plist-get info :special-tags-after-letter)))) 655 (cl-some (lambda (tag) (and (assoc-string tag special-tags) tag)) 656 (org-export-get-tags headline info)))) 657 658 (defun org-koma-letter--keyword-or-headline (plist-key pred info) 659 "Return the correct version of opening or closing. 660 PLIST-KEY should be a key in info, typically :opening 661 or :closing. PRED is a predicate run on headline to determine 662 which title to use which takes two arguments, a headline element 663 and an info plist. INFO is a plist holding contextual 664 information. Return the preferred candidate for the exported of 665 PLIST-KEY." 666 (let* ((keyword-candidate (plist-get info plist-key)) 667 (headline-candidate (when (and (plist-get info :with-headline-opening) 668 (or (plist-get info :special-headings) 669 (not keyword-candidate))) 670 (org-element-map (plist-get info :parse-tree) 671 'headline 672 (lambda (h) 673 (and (funcall pred h info) 674 (org-element-property :title h))) 675 info t)))) 676 (org-export-data (or headline-candidate keyword-candidate "") info))) 677 678 ;;;; Template 679 680 (defun org-koma-letter-template (contents info) 681 "Return complete document string after KOMA Scrlttr2 conversion. 682 CONTENTS is the transcoded contents string. INFO is a plist 683 holding export options." 684 (concat 685 ;; Time-stamp. 686 (and (plist-get info :time-stamp-file) 687 (format-time-string "%% Created %Y-%m-%d %a %H:%M\n")) 688 ;; LaTeX compiler 689 (org-latex--insert-compiler info) 690 ;; Document class and packages. 691 (org-latex-make-preamble info) 692 ;; Settings. They can come from three locations, in increasing 693 ;; order of precedence: global variables, LCO files and in-buffer 694 ;; settings. Thus, we first insert settings coming from global 695 ;; variables, then we insert LCO files, and, eventually, we insert 696 ;; settings coming from buffer keywords. 697 (org-koma-letter--build-settings 'global info) 698 (mapconcat (lambda (file) (format "\\LoadLetterOption{%s}\n" file)) 699 (split-string (or (plist-get info :lco) "")) 700 "") 701 (org-koma-letter--build-settings 'buffer info) 702 ;; Date. 703 (format "\\date{%s}\n" (org-export-data (org-export-get-date info) info)) 704 ;; Hyperref, document start, and subject and title. 705 (let* ((with-subject (plist-get info :with-subject)) 706 (with-title (plist-get info :with-title)) 707 (title-as-subject (and with-subject 708 (plist-get info :with-title-as-subject))) 709 (subject* (org-string-nw-p 710 (org-export-data (plist-get info :subject) info))) 711 (title* (and with-title 712 (org-string-nw-p 713 (org-export-data (plist-get info :title) info)))) 714 (subject (cond ((not with-subject) nil) 715 (title-as-subject (or subject* title*)) 716 (t subject*))) 717 (title (cond ((not with-title) nil) 718 (title-as-subject (and subject* title*)) 719 (t title*))) 720 (hyperref-template (plist-get info :latex-hyperref-template)) 721 (spec (append (list (cons ?t (or title subject ""))) 722 (org-latex--format-spec info)))) 723 (concat 724 (when (and with-subject (not (eq with-subject t))) 725 (format "\\KOMAoption{subject}{%s}\n" 726 (if (symbolp with-subject) with-subject 727 (mapconcat #'symbol-name with-subject ",")))) 728 ;; Hyperref. 729 (and (stringp hyperref-template) 730 (format-spec hyperref-template spec)) 731 ;; Document start. 732 "\\begin{document}\n\n" 733 ;; Subject and title. 734 (when subject (format "\\setkomavar{subject}{%s}\n" subject)) 735 (when title (format "\\setkomavar{title}{%s}\n" title)) 736 (when (or (org-string-nw-p title) (org-string-nw-p subject)) "\n"))) 737 ;; Letter start. 738 (let ((keyword-val (plist-get info :to-address)) 739 (heading-val (org-koma-letter--get-tagged-contents 'to))) 740 (format "\\begin{letter}{%%\n%s}\n\n" 741 (org-koma-letter--add-latex-newlines 742 (or (if (plist-get info :special-headings) 743 (or heading-val keyword-val) 744 (or keyword-val heading-val)) 745 "\\mbox{}")))) 746 ;; Opening. 747 (format "\\opening{%s}\n\n" 748 (org-koma-letter--keyword-or-headline 749 :opening 750 (lambda (h i) 751 (not (org-koma-letter--special-tag h i))) 752 info)) 753 ;; Letter body. 754 contents 755 ;; Closing. 756 (format "\\closing{%s}\n" 757 (org-koma-letter--keyword-or-headline 758 :closing 759 (lambda (h i) 760 (let ((special-tag (org-koma-letter--special-tag h i))) 761 (and special-tag 762 (string= "closing" special-tag)))) 763 info)) 764 (org-koma-letter--special-contents-inline 765 (plist-get info :special-tags-after-closing) info) 766 ;; Letter end. 767 "\n\\end{letter}\n" 768 (org-koma-letter--special-contents-inline 769 (plist-get info :special-tags-after-letter) info) 770 ;; Document end. 771 "\n\\end{document}")) 772 773 (defun org-koma-letter--build-settings (scope info) 774 "Build settings string according to type. 775 SCOPE is either `global' or `buffer'. INFO is a plist used as 776 a communication channel." 777 (let* ((check-scope 778 ;; Non-nil value when SETTING was defined in SCOPE. 779 (lambda (setting) 780 (let ((property (intern (format ":inbuffer-%s" setting)))) 781 (if (eq scope 'global) 782 (eq (plist-get info property) 'koma-letter:empty) 783 (not (eq (plist-get info property) 'koma-letter:empty)))))) 784 (heading-or-key-value 785 (lambda (heading key &optional scoped) 786 (let* ((heading-val 787 (org-koma-letter--get-tagged-contents heading)) 788 (key-val (org-string-nw-p (plist-get info key))) 789 (scopedp (funcall check-scope (or scoped heading)))) 790 (and (or (and key-val scopedp) heading-val) 791 (not (and (eq scope 'global) heading-val)) 792 (if scopedp key-val heading-val)))))) 793 (concat 794 ;; Name. 795 (let ((author (plist-get info :author))) 796 (and author 797 (funcall check-scope 'author) 798 (format "\\setkomavar{fromname}{%s}\n" 799 (org-export-data author info)))) 800 ;; From. 801 (let ((from (funcall heading-or-key-value 'from :from-address))) 802 (and from 803 (format "\\setkomavar{fromaddress}{%s}\n" 804 (org-koma-letter--add-latex-newlines from)))) 805 ;; Email. 806 (let ((email (plist-get info :email))) 807 (and email 808 (funcall check-scope 'email) 809 (format "\\setkomavar{fromemail}{%s}\n" email))) 810 (and (funcall check-scope 'with-email) 811 (format "\\KOMAoption{fromemail}{%s}\n" 812 (if (plist-get info :with-email) "true" "false"))) 813 ;; Phone number. 814 (let ((phone-number (plist-get info :phone-number))) 815 (and (org-string-nw-p phone-number) 816 (funcall check-scope 'phone-number) 817 (format "\\setkomavar{fromphone}{%s}\n" phone-number))) 818 (and (funcall check-scope 'with-phone) 819 (format "\\KOMAoption{fromphone}{%s}\n" 820 (if (plist-get info :with-phone) "true" "false"))) 821 ;; URL 822 (let ((url (plist-get info :url))) 823 (and (org-string-nw-p url) 824 (funcall check-scope 'url) 825 (format "\\setkomavar{fromurl}{%s}\n" url))) 826 (and (funcall check-scope 'with-url) 827 (format "\\KOMAoption{fromurl}{%s}\n" 828 (if (plist-get info :with-url) "true" "false"))) 829 ;; From Logo 830 (let ((from-logo (plist-get info :from-logo))) 831 (and (org-string-nw-p from-logo) 832 (funcall check-scope 'from-logo) 833 (format "\\setkomavar{fromlogo}{%s}\n" from-logo))) 834 (and (funcall check-scope 'with-from-logo) 835 (format "\\KOMAoption{fromlogo}{%s}\n" 836 (if (plist-get info :with-from-logo) "true" "false"))) 837 ;; Signature. 838 (let* ((heading-val 839 (and (plist-get info :with-headline-opening) 840 (pcase (org-koma-letter--get-tagged-contents 'closing) 841 ((and (pred org-string-nw-p) closing) (org-trim closing)) 842 (_ nil)))) 843 (signature (org-string-nw-p (plist-get info :signature))) 844 (signature-scope (funcall check-scope 'signature))) 845 (and (or (and signature signature-scope) 846 heading-val) 847 (not (and (eq scope 'global) heading-val)) 848 (format "\\setkomavar{signature}{%s}\n" 849 (if signature-scope signature heading-val)))) 850 ;; Back address. 851 (and (funcall check-scope 'with-backaddress) 852 (format "\\KOMAoption{backaddress}{%s}\n" 853 (if (plist-get info :with-backaddress) "true" "false"))) 854 ;; Place. 855 (let ((with-place-set (funcall check-scope 'with-place)) 856 (place-set (funcall check-scope 'place))) 857 (and (or (and with-place-set place-set) 858 (and (eq scope 'buffer) (or with-place-set place-set))) 859 (format "\\setkomavar{place}{%s}\n" 860 (if (plist-get info :with-place) (plist-get info :place) 861 "")))) 862 ;; Location. 863 (let ((location (funcall heading-or-key-value 'location :location))) 864 (and location 865 (format "\\setkomavar{location}{%s}\n" location))) 866 ;; Folding marks. 867 (and (funcall check-scope 'with-foldmarks) 868 (let ((foldmarks (plist-get info :with-foldmarks))) 869 (cond ((consp foldmarks) 870 (format "\\KOMAoptions{foldmarks=true,foldmarks=%s}\n" 871 (mapconcat #'symbol-name foldmarks ""))) 872 (foldmarks "\\KOMAoptions{foldmarks=true}\n") 873 (t "\\KOMAoptions{foldmarks=false}\n"))))))) 874 875 876 877 ;;; Commands 878 879 ;;;###autoload 880 (defun org-koma-letter-export-as-latex 881 (&optional async subtreep visible-only body-only ext-plist) 882 "Export current buffer as a KOMA Scrlttr2 letter. 883 884 If narrowing is active in the current buffer, only export its 885 narrowed part. 886 887 If a region is active, export that region. 888 889 A non-nil optional argument ASYNC means the process should happen 890 asynchronously. The resulting buffer should be accessible 891 through the `org-export-stack' interface. 892 893 When optional argument SUBTREEP is non-nil, export the sub-tree 894 at point, extracting information from the headline properties 895 first. 896 897 When optional argument VISIBLE-ONLY is non-nil, don't export 898 contents of hidden elements. 899 900 When optional argument BODY-ONLY is non-nil, only write code 901 between \"\\begin{letter}\" and \"\\end{letter}\". 902 903 EXT-PLIST, when provided, is a property list with external 904 parameters overriding Org default settings, but still inferior to 905 file-local settings. 906 907 Export is done in a buffer named \"*Org KOMA-LETTER Export*\". It 908 will be displayed if `org-export-show-temporary-export-buffer' is 909 non-nil." 910 (interactive) 911 (let (org-koma-letter-special-contents) 912 (org-export-to-buffer 'koma-letter "*Org KOMA-LETTER Export*" 913 async subtreep visible-only body-only ext-plist 914 (lambda () (LaTeX-mode))))) 915 916 ;;;###autoload 917 (defun org-koma-letter-export-to-latex 918 (&optional async subtreep visible-only body-only ext-plist) 919 "Export current buffer as a KOMA Scrlttr2 letter (tex). 920 921 If narrowing is active in the current buffer, only export its 922 narrowed part. 923 924 If a region is active, export that region. 925 926 A non-nil optional argument ASYNC means the process should happen 927 asynchronously. The resulting file should be accessible through 928 the `org-export-stack' interface. 929 930 When optional argument SUBTREEP is non-nil, export the sub-tree 931 at point, extracting information from the headline properties 932 first. 933 934 When optional argument VISIBLE-ONLY is non-nil, don't export 935 contents of hidden elements. 936 937 When optional argument BODY-ONLY is non-nil, only write code 938 between \"\\begin{letter}\" and \"\\end{letter}\". 939 940 EXT-PLIST, when provided, is a property list with external 941 parameters overriding Org default settings, but still inferior to 942 file-local settings. 943 944 When optional argument PUB-DIR is set, use it as the publishing 945 directory. 946 947 Return output file's name." 948 (interactive) 949 (let ((outfile (org-export-output-file-name ".tex" subtreep)) 950 (org-koma-letter-special-contents)) 951 (org-export-to-file 'koma-letter outfile 952 async subtreep visible-only body-only ext-plist))) 953 954 ;;;###autoload 955 (defun org-koma-letter-export-to-pdf 956 (&optional async subtreep visible-only body-only ext-plist) 957 "Export current buffer as a KOMA Scrlttr2 letter (pdf). 958 959 If narrowing is active in the current buffer, only export its 960 narrowed part. 961 962 If a region is active, export that region. 963 964 A non-nil optional argument ASYNC means the process should happen 965 asynchronously. The resulting file should be accessible through 966 the `org-export-stack' interface. 967 968 When optional argument SUBTREEP is non-nil, export the sub-tree 969 at point, extracting information from the headline properties 970 first. 971 972 When optional argument VISIBLE-ONLY is non-nil, don't export 973 contents of hidden elements. 974 975 When optional argument BODY-ONLY is non-nil, only write code 976 between \"\\begin{letter}\" and \"\\end{letter}\". 977 978 EXT-PLIST, when provided, is a property list with external 979 parameters overriding Org default settings, but still inferior to 980 file-local settings. 981 982 Return PDF file's name." 983 (interactive) 984 (let ((file (org-export-output-file-name ".tex" subtreep)) 985 (org-koma-letter-special-contents)) 986 (org-export-to-file 'koma-letter file 987 async subtreep visible-only body-only ext-plist 988 #'org-latex-compile))) 989 990 991 (provide 'ox-koma-letter) 992 ;;; ox-koma-letter.el ends here