ox-koma-letter.el (40615B)
1 ;;; ox-koma-letter.el --- KOMA Scrlttr2 Backend for Org Export Engine -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2007-2024 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, text, 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 backend, 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' backend (see 38 ;; `org-latex-packages-alist'), this backend 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 Backend 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 INFO is the information plist possibly holding :special-tags-as-macro 575 property. See `org-koma-letter-special-tags-as-macro'. 576 577 The function is used for inserting content of special headings 578 such as the one tagged with PS." 579 (mapconcat 580 (lambda (keyword) 581 (let* ((name (org-koma-letter--get-value keyword)) 582 (value (org-koma-letter--get-tagged-contents name)) 583 (macrop (memq keyword (plist-get info :special-tags-as-macro)))) 584 (cond ((not value) nil) 585 (macrop (format "\\%s{%s}\n" name value)) 586 (t value)))) 587 keywords 588 "\n")) 589 590 591 (defun org-koma-letter--add-latex-newlines (string) 592 "Replace regular newlines with LaTeX newlines (i.e. `\\\\') in STRING. 593 Return a new string." 594 (let ((str (org-trim string))) 595 (when (org-string-nw-p str) 596 (replace-regexp-in-string "\n" "\\\\\\\\\n" str)))) 597 598 599 600 ;;; Transcode Functions 601 602 ;;;; Export Block 603 604 (defun org-koma-letter-export-block (export-block _contents _info) 605 "Transcode an EXPORT-BLOCK element into KOMA Scrlttr2 code. 606 CONTENTS is nil. INFO is a plist used as a communication 607 channel." 608 (when (member (org-element-property :type export-block) 609 '("KOMA-LETTER" "LATEX")) 610 (org-remove-indentation (org-element-property :value export-block)))) 611 612 ;;;; Export Snippet 613 614 (defun org-koma-letter-export-snippet (export-snippet _contents _info) 615 "Transcode an EXPORT-SNIPPET object into KOMA Scrlttr2 code. 616 CONTENTS is nil. INFO is a plist used as a communication 617 channel." 618 (when (memq (org-export-snippet-backend export-snippet) '(latex koma-letter)) 619 (org-element-property :value export-snippet))) 620 621 ;;;; Keyword 622 623 (defun org-koma-letter-keyword (keyword contents info) 624 "Transcode a KEYWORD element into KOMA Scrlttr2 code. 625 CONTENTS is nil. INFO is a plist used as a communication 626 channel." 627 (let ((key (org-element-property :key keyword)) 628 (value (org-element-property :value keyword))) 629 ;; Handle specifically KOMA-LETTER keywords. Otherwise, fallback 630 ;; to `latex' backend. 631 (if (equal key "KOMA-LETTER") value 632 (org-export-with-backend 'latex keyword contents info)))) 633 634 ;; Headline 635 636 (defun org-koma-letter-headline (headline contents info) 637 "Transcode a HEADLINE element from Org to LaTeX. 638 CONTENTS holds the contents of the headline. INFO is a plist 639 holding contextual information. 640 641 Note that if a headline is tagged with a tag from 642 `org-koma-letter-special-tags' it will not be exported, but 643 stored in `org-koma-letter-special-contents' and included at the 644 appropriate place." 645 (let ((special-tag (org-koma-letter--special-tag headline info))) 646 (if (not special-tag) 647 contents 648 (push (cons special-tag contents) org-koma-letter-special-contents) 649 ""))) 650 651 (defun org-koma-letter--special-tag (headline info) 652 "Non-nil if HEADLINE is a special headline. 653 INFO is a plist holding contextual information. Return first 654 special tag headline." 655 (let ((special-tags (append 656 (plist-get info :special-tags-in-letter) 657 (plist-get info :special-tags-after-closing) 658 (plist-get info :special-tags-after-letter)))) 659 (cl-some (lambda (tag) (and (assoc-string tag special-tags) tag)) 660 (org-export-get-tags headline info)))) 661 662 (defun org-koma-letter--keyword-or-headline (plist-key pred info) 663 "Return the correct version of opening or closing. 664 PLIST-KEY should be a key in info, typically :opening 665 or :closing. PRED is a predicate run on headline to determine 666 which title to use which takes two arguments, a headline element 667 and an info plist. INFO is a plist holding contextual 668 information. Return the preferred candidate for the exported of 669 PLIST-KEY." 670 (let* ((keyword-candidate (plist-get info plist-key)) 671 (headline-candidate (when (and (plist-get info :with-headline-opening) 672 (or (plist-get info :special-headings) 673 (not keyword-candidate))) 674 (org-element-map (plist-get info :parse-tree) 675 'headline 676 (lambda (h) 677 (and (funcall pred h info) 678 (org-element-property :title h))) 679 info t)))) 680 (org-export-data (or headline-candidate keyword-candidate "") info))) 681 682 ;;;; Template 683 684 (defun org-koma-letter-template (contents info) 685 "Return complete document string after KOMA Scrlttr2 conversion. 686 CONTENTS is the transcoded contents string. INFO is a plist 687 holding export options." 688 (concat 689 ;; Timestamp. 690 (and (plist-get info :time-stamp-file) 691 (format-time-string "%% Created %Y-%m-%d %a %H:%M\n")) 692 ;; LaTeX compiler 693 (org-latex--insert-compiler info) 694 ;; Document class and packages. 695 (org-latex-make-preamble info) 696 ;; Settings. They can come from three locations, in increasing 697 ;; order of precedence: global variables, LCO files and in-buffer 698 ;; settings. Thus, we first insert settings coming from global 699 ;; variables, then we insert LCO files, and, eventually, we insert 700 ;; settings coming from buffer keywords. 701 (org-koma-letter--build-settings 'global info) 702 (mapconcat (lambda (file) (format "\\LoadLetterOption{%s}\n" file)) 703 (split-string (or (plist-get info :lco) "")) 704 "") 705 (org-koma-letter--build-settings 'buffer info) 706 ;; Date. 707 (format "\\date{%s}\n" (org-export-data (org-export-get-date info) info)) 708 ;; Hyperref, document start, and subject and title. 709 (let* ((with-subject (plist-get info :with-subject)) 710 (with-title (plist-get info :with-title)) 711 (title-as-subject (and with-subject 712 (plist-get info :with-title-as-subject))) 713 (subject* (org-string-nw-p 714 (org-export-data (plist-get info :subject) info))) 715 (title* (and with-title 716 (org-string-nw-p 717 (org-export-data (plist-get info :title) info)))) 718 (subject (cond ((not with-subject) nil) 719 (title-as-subject (or subject* title*)) 720 (t subject*))) 721 (title (cond ((not with-title) nil) 722 (title-as-subject (and subject* title*)) 723 (t title*))) 724 (hyperref-template (plist-get info :latex-hyperref-template)) 725 (spec (append (list (cons ?t (or title subject ""))) 726 (org-latex--format-spec info)))) 727 (concat 728 (when (and with-subject (not (eq with-subject t))) 729 (format "\\KOMAoption{subject}{%s}\n" 730 (if (symbolp with-subject) with-subject 731 (mapconcat #'symbol-name with-subject ",")))) 732 ;; Hyperref. 733 (and (stringp hyperref-template) 734 (format-spec hyperref-template spec)) 735 ;; Document start. 736 "\\begin{document}\n\n" 737 ;; Subject and title. 738 (when subject (format "\\setkomavar{subject}{%s}\n" subject)) 739 (when title (format "\\setkomavar{title}{%s}\n" title)) 740 (when (or (org-string-nw-p title) (org-string-nw-p subject)) "\n"))) 741 ;; Letter start. 742 (let ((keyword-val (plist-get info :to-address)) 743 (heading-val (org-koma-letter--get-tagged-contents 'to))) 744 (format "\\begin{letter}{%%\n%s}\n\n" 745 (org-koma-letter--add-latex-newlines 746 (or (if (plist-get info :special-headings) 747 (or heading-val keyword-val) 748 (or keyword-val heading-val)) 749 "\\mbox{}")))) 750 ;; Opening. 751 (format "\\opening{%s}\n\n" 752 (org-koma-letter--keyword-or-headline 753 :opening 754 (lambda (h i) 755 (not (org-koma-letter--special-tag h i))) 756 info)) 757 ;; Letter body. 758 contents 759 ;; Closing. 760 (format "\\closing{%s}\n" 761 (org-koma-letter--keyword-or-headline 762 :closing 763 (lambda (h i) 764 (let ((special-tag (org-koma-letter--special-tag h i))) 765 (and special-tag 766 (string= "closing" special-tag)))) 767 info)) 768 (org-koma-letter--special-contents-inline 769 (plist-get info :special-tags-after-closing) info) 770 ;; Letter end. 771 "\n\\end{letter}\n" 772 (org-koma-letter--special-contents-inline 773 (plist-get info :special-tags-after-letter) info) 774 ;; Document end. 775 "\n\\end{document}")) 776 777 (defun org-koma-letter--build-settings (scope info) 778 "Build settings string according to type. 779 SCOPE is either `global' or `buffer'. INFO is a plist used as 780 a communication channel." 781 (let* ((check-scope 782 ;; Non-nil value when SETTING was defined in SCOPE. 783 (lambda (setting) 784 (let ((property (intern (format ":inbuffer-%s" setting)))) 785 (if (eq scope 'global) 786 (eq (plist-get info property) 'koma-letter:empty) 787 (not (eq (plist-get info property) 'koma-letter:empty)))))) 788 (heading-or-key-value 789 (lambda (heading key &optional scoped) 790 (let* ((heading-val 791 (org-koma-letter--get-tagged-contents heading)) 792 (key-val (org-string-nw-p (plist-get info key))) 793 (scopedp (funcall check-scope (or scoped heading)))) 794 (and (or (and key-val scopedp) heading-val) 795 (not (and (eq scope 'global) heading-val)) 796 (if scopedp key-val heading-val)))))) 797 (concat 798 ;; Name. 799 (let ((author (plist-get info :author))) 800 (and author 801 (funcall check-scope 'author) 802 (format "\\setkomavar{fromname}{%s}\n" 803 (org-export-data author info)))) 804 ;; From. 805 (let ((from (funcall heading-or-key-value 'from :from-address))) 806 (and from 807 (format "\\setkomavar{fromaddress}{%s}\n" 808 (org-koma-letter--add-latex-newlines from)))) 809 ;; Email. 810 (let ((email (plist-get info :email))) 811 (and email 812 (funcall check-scope 'email) 813 (format "\\setkomavar{fromemail}{%s}\n" email))) 814 (and (funcall check-scope 'with-email) 815 (format "\\KOMAoption{fromemail}{%s}\n" 816 (if (plist-get info :with-email) "true" "false"))) 817 ;; Phone number. 818 (let ((phone-number (plist-get info :phone-number))) 819 (and (org-string-nw-p phone-number) 820 (funcall check-scope 'phone-number) 821 (format "\\setkomavar{fromphone}{%s}\n" phone-number))) 822 (and (funcall check-scope 'with-phone) 823 (format "\\KOMAoption{fromphone}{%s}\n" 824 (if (plist-get info :with-phone) "true" "false"))) 825 ;; URL 826 (let ((url (plist-get info :url))) 827 (and (org-string-nw-p url) 828 (funcall check-scope 'url) 829 (format "\\setkomavar{fromurl}{%s}\n" url))) 830 (and (funcall check-scope 'with-url) 831 (format "\\KOMAoption{fromurl}{%s}\n" 832 (if (plist-get info :with-url) "true" "false"))) 833 ;; From Logo 834 (let ((from-logo (plist-get info :from-logo))) 835 (and (org-string-nw-p from-logo) 836 (funcall check-scope 'from-logo) 837 (format "\\setkomavar{fromlogo}{%s}\n" from-logo))) 838 (and (funcall check-scope 'with-from-logo) 839 (format "\\KOMAoption{fromlogo}{%s}\n" 840 (if (plist-get info :with-from-logo) "true" "false"))) 841 ;; Signature. 842 (let* ((heading-val 843 (and (plist-get info :with-headline-opening) 844 (pcase (org-koma-letter--get-tagged-contents 'closing) 845 ((and (pred org-string-nw-p) closing) (org-trim closing)) 846 (_ nil)))) 847 (signature (org-string-nw-p (plist-get info :signature))) 848 (signature-scope (funcall check-scope 'signature))) 849 (and (or (and signature signature-scope) 850 heading-val) 851 (not (and (eq scope 'global) heading-val)) 852 (format "\\setkomavar{signature}{%s}\n" 853 (if signature-scope signature heading-val)))) 854 ;; Back address. 855 (and (funcall check-scope 'with-backaddress) 856 (format "\\KOMAoption{backaddress}{%s}\n" 857 (if (plist-get info :with-backaddress) "true" "false"))) 858 ;; Place. 859 (let ((with-place-set (funcall check-scope 'with-place)) 860 (place-set (funcall check-scope 'place))) 861 (and (or (and with-place-set place-set) 862 (and (eq scope 'buffer) (or with-place-set place-set))) 863 (format "\\setkomavar{place}{%s}\n" 864 (if (plist-get info :with-place) (plist-get info :place) 865 "")))) 866 ;; Location. 867 (let ((location (funcall heading-or-key-value 'location :location))) 868 (and location 869 (format "\\setkomavar{location}{%s}\n" location))) 870 ;; Folding marks. 871 (and (funcall check-scope 'with-foldmarks) 872 (let ((foldmarks (plist-get info :with-foldmarks))) 873 (cond ((consp foldmarks) 874 (format "\\KOMAoptions{foldmarks=true,foldmarks=%s}\n" 875 (mapconcat #'symbol-name foldmarks ""))) 876 (foldmarks "\\KOMAoptions{foldmarks=true}\n") 877 (t "\\KOMAoptions{foldmarks=false}\n"))))))) 878 879 880 881 ;;; Commands 882 883 ;;;###autoload 884 (defun org-koma-letter-export-as-latex 885 (&optional async subtreep visible-only body-only ext-plist) 886 "Export current buffer as a KOMA Scrlttr2 letter. 887 888 If narrowing is active in the current buffer, only export its 889 narrowed part. 890 891 If a region is active, export that region. 892 893 A non-nil optional argument ASYNC means the process should happen 894 asynchronously. The resulting buffer should be accessible 895 through the `org-export-stack' interface. 896 897 When optional argument SUBTREEP is non-nil, export the sub-tree 898 at point, extracting information from the headline properties 899 first. 900 901 When optional argument VISIBLE-ONLY is non-nil, don't export 902 contents of hidden elements. 903 904 When optional argument BODY-ONLY is non-nil, only write code 905 between \"\\begin{letter}\" and \"\\end{letter}\". 906 907 EXT-PLIST, when provided, is a property list with external 908 parameters overriding Org default settings, but still inferior to 909 file-local settings. 910 911 Export is done in a buffer named \"*Org KOMA-LETTER Export*\". It 912 will be displayed if `org-export-show-temporary-export-buffer' is 913 non-nil." 914 (interactive) 915 (let (org-koma-letter-special-contents) 916 (org-export-to-buffer 'koma-letter "*Org KOMA-LETTER Export*" 917 async subtreep visible-only body-only ext-plist 918 (if (fboundp 'major-mode-remap) 919 (major-mode-remap 'latex-mode) 920 #'LaTeX-mode)))) 921 922 ;;;###autoload 923 (defun org-koma-letter-export-to-latex 924 (&optional async subtreep visible-only body-only ext-plist) 925 "Export current buffer as a KOMA Scrlttr2 letter (tex). 926 927 If narrowing is active in the current buffer, only export its 928 narrowed part. 929 930 If a region is active, export that region. 931 932 A non-nil optional argument ASYNC means the process should happen 933 asynchronously. The resulting file should be accessible through 934 the `org-export-stack' interface. 935 936 When optional argument SUBTREEP is non-nil, export the sub-tree 937 at point, extracting information from the headline properties 938 first. 939 940 When optional argument VISIBLE-ONLY is non-nil, don't export 941 contents of hidden elements. 942 943 When optional argument BODY-ONLY is non-nil, only write code 944 between \"\\begin{letter}\" and \"\\end{letter}\". 945 946 EXT-PLIST, when provided, is a property list with external 947 parameters overriding Org default settings, but still inferior to 948 file-local settings. 949 950 When optional argument PUB-DIR is set, use it as the publishing 951 directory. 952 953 Return output file's name." 954 (interactive) 955 (let ((outfile (org-export-output-file-name ".tex" subtreep)) 956 (org-koma-letter-special-contents)) 957 (org-export-to-file 'koma-letter outfile 958 async subtreep visible-only body-only ext-plist))) 959 960 ;;;###autoload 961 (defun org-koma-letter-export-to-pdf 962 (&optional async subtreep visible-only body-only ext-plist) 963 "Export current buffer as a KOMA Scrlttr2 letter (pdf). 964 965 If narrowing is active in the current buffer, only export its 966 narrowed part. 967 968 If a region is active, export that region. 969 970 A non-nil optional argument ASYNC means the process should happen 971 asynchronously. The resulting file should be accessible through 972 the `org-export-stack' interface. 973 974 When optional argument SUBTREEP is non-nil, export the sub-tree 975 at point, extracting information from the headline properties 976 first. 977 978 When optional argument VISIBLE-ONLY is non-nil, don't export 979 contents of hidden elements. 980 981 When optional argument BODY-ONLY is non-nil, only write code 982 between \"\\begin{letter}\" and \"\\end{letter}\". 983 984 EXT-PLIST, when provided, is a property list with external 985 parameters overriding Org default settings, but still inferior to 986 file-local settings. 987 988 Return PDF file's name." 989 (interactive) 990 (let ((file (org-export-output-file-name ".tex" subtreep)) 991 (org-koma-letter-special-contents)) 992 (org-export-to-file 'koma-letter file 993 async subtreep visible-only body-only ext-plist 994 #'org-latex-compile))) 995 996 997 (provide 'ox-koma-letter) 998 ;;; ox-koma-letter.el ends here