org-exp-generic.el: Fix bug with closing bodies
[org-mode.git] / contrib / lisp / org-export-generic.el
blob7b4a30d41c056eabf1a10f6bba2aa17e500e5b0e
1 ;;; org-export-generic.el --- Export frameworg with custom backends
3 ;; Copyright (C) 2009 Free Software Foundation, Inc.
5 ;; Author: Wes Hardaker <hardaker at users dot sourceforge dot net>
6 ;; Keywords: outlines, hypermedia, calendar, wp, export
7 ;; Homepage: http://orgmode.org
8 ;; Version: 6.25trans
9 ;; Acks: Much of this code was stolen form the ascii export from Carsten
11 ;; This file is not yet part of GNU Emacs.
13 ;; GNU Emacs is free software: you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation, either version 3 of the License, or
16 ;; (at your option) any later version.
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
26 ;; ----------------------------------------------------------------------
28 ;; OVERVIEW
30 ;; org-export-generic is basically a simple translation system that
31 ;; knows how to parse at least most of a .org buffer and then add
32 ;; various formatting prefixes before and after each section type. It
33 ;; does this by examining a property list stored in org-generic-alist.
34 ;; You can dynamically add propety lists of your own using the
35 ;; org-set-generic-type function:
37 ;; (org-set-generic-type
38 ;; "really-basic-text"
39 ;; '(:file-suffix ".txt"
40 ;; :key-binding ?R
42 ;; :title-format "=== %s ===\n"
43 ;; :body-header-section-numbers t
44 ;; :body-header-section-number-format "%s) "
45 ;; :body-section-header-prefix "\n"
46 ;; :body-section-header-suffix "\n"
47 ;; :body-line-format " %s\n"
48 ;; :body-line-wrap 75
49 ;; ))
51 ;; Note: Upper case key-bindings are reserved for your use. Lower
52 ;; case key bindings may conflict with future export-generic
53 ;; publications.
55 ;; Then run org-export (ctrl-c ctrl-e) and select generic or run
56 ;; org-export-generic. You'll then be prompted with a list of export
57 ;; types to choose from which will include your new type assigned to
58 ;; the key "r".
60 ;; ----------------------------------------------------------------------
62 ;; TODO (non-ordered)
63 ;; * handle function references
64 ;; * handle other types of multi-complex-listy-things to do
65 ;; ideas: (t ?- "%s" ?-)
66 ;; * handle indent specifiers better
67 ;; ideas: (4 ?\ "%s")
68 ;; * need flag to remove indents from body text
69 ;; * handle links
70 ;; * handle internationalization strings better
71 ;; * date/author/etc needs improvment (internationalization too)
72 ;; * allow specifying of section ordering
73 ;; ideas: :ordering ("header" "toc" "body" "footer")
74 ;; ^ matches current hard coded ordering
75 ;; * err, actually *do* a footer
76 ;; * deal with usage of org globals
77 ;; *** should we even consider them, or let the per-section specifiers do it
78 ;; *** answer: remove; mostly removed now
79 ;; * deal with interactive support for picking a export specifier label
80 ;; * char specifiers that need extra length because of formatting
81 ;; idea: (?- 4) for 4-longer
82 ;; * centering specifier
83 ;; idea: ('center " -- %s -- ")
84 ;; * remove more of the unneeded export-to-ascii copy code
85 ;; * tags
86 ;; *** supported now, but need separate format per tag
87 ;; *** allow different open/closing prefixes
88 ;; * properties
89 ;; * drawers
90 ;; * oh my
91 ;; * optmization (many plist extracts should be in (let) vars
92 ;; * define defcustom spec for the specifier list
94 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
96 ;;; Commentary:
98 (require 'org-exp)
99 (require 'assoc)
101 (defgroup org-export-generic nil
102 "Options specific for ASCII export of Org-mode files."
103 :tag "Org Export ASCII"
104 :group 'org-export)
106 (defcustom org-export-generic-links-to-notes t
107 "Non-nil means, convert links to notes before the next headline.
108 When nil, the link will be exported in place. If the line becomes long
109 in this way, it will be wrapped."
110 :group 'org-export-generic
111 :type 'boolean)
114 (defvar org-generic-current-indentation nil) ; For communication
116 (defvar org-generic-alist
119 ;; generic DEMO exporter
121 ;; (this tries to use every specifier for demo purposes)
123 ("demo"
124 :file-suffix ".txt"
125 :key-binding ?d
127 :header-prefix "<header>\n"
128 :header-suffix "</header>\n"
130 :author-export t
131 :tags-export t
133 :drawers-export t
136 :title-prefix ?=
137 :title-format "<h1>%s</h1>\n"
138 :title-suffix ?=
140 :date-export t
141 :date-prefix "<date>"
142 :date-format "<br /><b>Date:</b> <i>%s</i><br />"
143 :date-suffix "</date>\n\n"
145 :toc-export t
146 :toc-header-prefix "<tocname>\n"
147 :toc-header-format "__%s__\n"
148 :toc-header-suffix "</tocname>\n"
150 :toc-prefix "<toc>\n"
151 :toc-suffix "</toc>\n"
153 :toc-section-numbers t
154 :toc-section-number-format "\#(%s) "
155 :toc-format "--%s--"
156 :toc-format-with-todo "!!%s!!\n"
157 :toc-indent-char ?\
158 :toc-indent-depth 4
160 :toc-tags-export t
161 :toc-tags-prefix " <tags>"
162 :toc-tags-format "*%s*"
163 :toc-tags-suffix "</tags>\n"
164 :toc-tags-none-string "\n"
166 :body-header-section-numbers 3 ; t = all, nil = none
168 ; lists indicate different things per level
169 ; list contents or straight value can either be a
170 ; ?x char reference for printing strings that match the header len
171 ; "" string to print directly
172 :body-section-header-prefix ("<h1>" "<h2>" "<h3>"
173 "<h4>" "<h5>" "<h6>")
174 :body-section-header-format "%s"
175 :body-section-header-suffix ("</h1>\n" "</h2>\n" "</h3>\n"
176 "</h4>\n" "</h5>\n" "</h6>\n")
178 :timestamps-export t
179 :priorities-export t
180 :todo-keywords-export t
182 :body-tags-export t
183 :body-tags-prefix " <tags>"
184 :body-tags-suffix "</tags>\n"
186 ; section prefixes/suffixes can be direct strings or lists as well
187 :body-section-prefix "<secprefix>\n"
188 :body-section-suffix "</secsuffix>\n"
189 ; :body-section-prefix ("<sec1>\n" "<sec2>\n" "<sec3>\n")
190 ; :body-section-suffix ("</sec1>\n" "</sec2>\n" "</sec3>\n")
193 ; if preformated text should be included (eg, : prefixed)
194 :body-line-export-preformated t
195 :body-line-fixed-prefix "<pre>\n"
196 :body-line-fixed-suffix "\n</pre>\n"
197 :body-line-fixed-format "%s\n"
200 :body-list-prefix "<list>\n"
201 :body-list-suffix "</list>\n"
202 :body-list-format "<li>%s</li>\n"
204 :body-number-list-prefix "<ol>\n"
205 :body-number-list-suffix "</ol>\n"
206 :body-number-list-format "<li>%s</li>\n"
207 :body-number-list-leave-number t
209 :body-list-checkbox-todo "<checkbox type=\"todo\">"
210 :body-list-checkbox-todo-end "</checkbox (todo)>"
211 :body-list-checkbox-done "<checkbox type=\"done\">"
212 :body-list-checkbox-done-end "</checkbox (done)>"
213 :body-list-checkbox-half "<checkbox type=\"half\">"
214 :body-list-checkbox-half-end "</checkbox (half)>"
219 ; other body lines
220 :body-line-format "%s"
221 :body-line-wrap 60 ; wrap at 60 chars
223 ; print above and below all body parts
224 :body-text-prefix "<p>\n"
225 :body-text-suffix "</p>\n"
230 ;; ascii exporter
232 ;; (close to the original ascii specifier)
234 ("ascii"
235 :file-suffix ".txt"
236 :key-binding ?a
238 :header-prefix ""
239 :header-suffix ""
241 :title-prefix ?=
242 :title-format "%s\n"
243 :title-suffix ?=
245 :date-export t
246 :date-prefix ""
247 :date-format "Date: %s\n"
248 :date-suffix ""
250 :toc-header-prefix ""
251 :toc-header-format "%s\n"
252 :toc-header-suffix ?=
254 :toc-export t
255 :toc-section-numbers t
256 :toc-section-number-format "%s "
257 :toc-format "%s\n"
258 :toc-format-with-todo "%s (*)\n"
259 :toc-indent-char ?\
260 :toc-indent-depth 4
262 :body-header-section-numbers 3
263 :body-section-prefix "\n"
265 ; :body-section-header-prefix "\n"
266 ; :body-section-header-format "%s\n"
267 ; :body-section-header-suffix (?\$ ?\# ?^ ?\~ ?\= ?\-)
269 :body-section-header-prefix ("" "" "" "* " " + " " - ")
270 :body-section-header-format "%s\n"
271 :body-section-header-suffix (?~ ?= ?- "\n" "\n" "\n")
273 ; :body-section-marker-prefix ""
274 ; :body-section-marker-chars (?\$ ?\# ?^ ?\~ ?\= ?\-)
275 ; :body-section-marker-suffix "\n"
277 :body-line-export-preformated t
278 :body-line-format "%s\n"
279 :body-line-wrap 75
281 ; :body-text-prefix "<t>\n"
282 ; :body-text-suffix "</t>\n"
285 :body-bullet-list-prefix (?* ?+ ?-)
286 ; :body-bullet-list-suffix (?* ?+ ?-)
290 ;; wikipedia
292 ("wikipedia"
293 :file-suffix ".txt"
294 :key-binding ?w
296 :header-prefix ""
297 :header-suffix ""
299 :title-format "= %s =\n"
301 :date-export nil
303 :toc-export nil
305 :body-header-section-numbers nil
306 :body-section-prefix "\n"
308 :body-section-header-prefix ("= " "== " "=== "
309 "==== " "===== " "====== ")
310 :body-section-header-suffix (" =\n\n" " ==\n\n" " ===\n\n"
311 " ====\n\n" " =====\n\n" " ======\n\n")
313 :body-line-export-preformated t ;; yes/no/maybe???
314 :body-line-format "%s\n"
315 :body-line-wrap 75
317 :body-line-fixed-format " %s\n"
319 :body-list-format "* %s\n"
320 :body-number-list-format "# %s\n"
322 :body-bullet-list-prefix ("* " "** " "*** " "**** " "***** ")
326 ;; minimal html exporter
328 ("html"
329 ;; simple html output
330 :file-suffix ".html"
331 :key-binding ?h
333 :header-prefix "<body>"
335 :title-format "<h1>%s</h1>\n\n"
337 :date-export t
338 :date-format "<br /><b>Date:</b> <i>%s</i><br />\n\n"
340 :toc-export nil
342 :body-header-section-numbers 3
344 :body-section-header-prefix ("<h1>" "<h2>" "<h3>"
345 "<h4>" "<h5>" "<h6>")
346 :body-section-header-format "%s"
347 :body-section-header-suffix ("</h1>\n" "</h2>\n" "</h3>\n"
348 "</h4>\n" "</h5>\n" "</h6>\n")
350 :body-section-prefix "<secprefix>\n"
351 :body-section-suffix "</secsuffix>\n"
352 ; :body-section-prefix ("<sec1>\n" "<sec2>\n" "<sec3>\n")
353 ; :body-section-suffix ("</sec1>\n" "</sec2>\n" "</sec3>\n")
355 :body-line-export-preformated t
356 :body-line-format "%s\n"
358 :body-text-prefix "<p>\n"
359 :body-text-suffix "</p>\n"
361 :body-bullet-list-prefix (?* ?+ ?-)
362 ; :body-bullet-list-suffix (?* ?+ ?-)
366 ;; internet-draft .xml for xml2rfc exporter
368 ("ietfid"
369 ;; this tries to use every specifier for demo purposes
370 :file-suffix ".xml"
371 :key-binding ?i
373 :title-prefix "<?xml version=\"1.0\"\?>
374 <!DOCTYPE rfc SYSTEM \"rfc2629.dtd\" [
375 <!ENTITY rfcs PUBLIC '' 'blah'>
376 <?rfc strict=\"yes\" ?>
377 <?rfc toc=\"yes\" ?>
378 <?rfc tocdepth=\"4\" ?>
379 <?rfc symrefs=\"yes\" ?>
380 <?rfc compact=\"yes\" ?>
381 <?rfc subcompact=\"no\" ?>
382 <rfc category=\"std\" ipr=\"pre5378Trust200902\" docName=\"FILLME.txt\">
383 <front>
385 :title-format "<title abbrev=\"ABBREV HERE\">\n%s\n</title>\n"
386 :title-suffix "<author initials=\"A.A\" surname=\"LASTNAME\" fullname=\"FULL NAME\">
387 <organization>Comany, Inc..</organization>
388 <address>
389 <postal>
390 <street></street>
391 <city></city>
392 <region></region>
393 <code></code>
394 <country></country>
395 </postal>
396 <phone></phone>
397 <email></email>
398 </address>
399 </author>
400 <date month=\"FILLMONTH\" year=\"FILLYEAR\"/>
401 <area>Operations and Management</area>
402 <workgroup>FIXME</workgroup>
403 <abstract>\n"
404 :date-export nil
406 :toc-export nil
408 :body-header-section-numbers nil
410 :body-section-header-format "<section title=\"%s\">\n"
411 :body-section-suffix "</section>\n"
413 ; if preformated text should be included (eg, : prefixed)
414 :body-line-export-preformated t
415 :body-line-fixed-prefix "<figure>\n<artwork>\n"
416 :body-line-fixed-suffix "\n</artwork>\n</figure>\n"
418 ; other body lines
419 :body-line-format "%s"
420 :body-line-wrap 75
422 ; print above and below all body parts
423 :body-text-prefix "<t>\n"
424 :body-text-suffix "</t>\n"
426 :body-list-prefix "<list style=\"symbols\">\n"
427 :body-list-suffix "</list>\n"
428 :body-list-format "<t>%s</t>\n"
432 "A assoc list of property lists to specify export definitions"
435 (setq org-generic-export-type "demo")
437 (defvar org-export-generic-section-type "")
438 (defvar org-export-generic-section-suffix "")
440 ;;;###autoload
441 (defun org-set-generic-type (type definition)
442 "Adds a TYPE and DEFINITION to the existing list of defined generic
443 export definitions."
444 (aput 'org-generic-alist type definition))
446 (defun org-export-generic-remember-section (type suffix &optional prefix)
447 (setq org-export-generic-section-type type)
448 (setq org-export-generic-section-suffix suffix)
449 (if prefix
450 (insert prefix))
453 (defun org-export-generic-check-section (type &optional prefix suffix)
454 "checks to see if type is already in use, or we're switching parts
455 If we're switching, then insert a potentially previously remembered
456 suffix, and insert the current prefix immediately and then save the
457 suffix a later change time."
459 (when (not (equal type org-export-generic-section-type))
460 (if org-export-generic-section-suffix
461 (insert org-export-generic-section-suffix))
462 (setq org-export-generic-section-type type)
463 (setq org-export-generic-section-suffix suffix)
464 (if prefix
465 (insert prefix))))
467 ;;;###autoload
468 (defun org-export-generic (arg)
469 "Export the outline as generic output.
470 If there is an active region, export only the region.
471 The prefix ARG specifies how many levels of the outline should become
472 underlined headlines. The default is 3."
473 (interactive "P")
474 (setq-default org-todo-line-regexp org-todo-line-regexp)
475 (let* ((opt-plist (org-combine-plists (org-default-export-plist)
476 (org-infile-export-plist)))
477 (region-p (org-region-active-p))
478 (rbeg (and region-p (region-beginning)))
479 (rend (and region-p (region-end)))
480 (subtree-p
481 (when region-p
482 (save-excursion
483 (goto-char rbeg)
484 (and (org-at-heading-p)
485 (>= (org-end-of-subtree t t) rend)))))
486 (level-offset (if subtree-p
487 (save-excursion
488 (goto-char rbeg)
489 (+ (funcall outline-level)
490 (if org-odd-levels-only 1 0)))
492 (opt-plist (setq org-export-opt-plist
493 (if subtree-p
494 (org-export-add-subtree-options opt-plist rbeg)
495 opt-plist)))
497 helpstart
498 (bogus (mapc (lambda (x)
499 (setq helpstart
500 (concat helpstart "\["
501 (char-to-string
502 (plist-get (cdr x) :key-binding))
503 "] " (car x) "\n")))
504 org-generic-alist))
506 (help (concat helpstart "
508 \[ ] the current setting of the org-generic-export-type variable
511 (cmds
513 (append
514 (mapcar (lambda (x)
515 (list
516 (plist-get (cdr x) :key-binding)
517 (car x)))
518 org-generic-alist)
519 (list (list ? "default"))))
521 r1 r2 ass
523 ;; read in the type to use
524 (export-plist
525 (progn
526 (save-excursion
527 (save-window-excursion
528 (delete-other-windows)
529 (with-output-to-temp-buffer "*Org Export/Generic Styles Help*"
530 (princ help))
531 (org-fit-window-to-buffer (get-buffer-window
532 "*Org Export/Generic Styles Help*"))
533 (message "Select command: ")
534 (setq r1 (read-char-exclusive))))
535 (setq r2 (if (< r1 27) (+ r1 96) r1))
536 (unless (setq ass (cadr (assq r2 cmds)))
537 (error "No command associated with key %c" r1))
539 (cdr (assoc
540 (if (equal ass "default") org-generic-export-type ass)
541 org-generic-alist))))
543 (custom-times org-display-custom-times)
544 (org-generic-current-indentation '(0 . 0))
545 (level 0) (old-level 0) line txt lastwastext
546 (umax nil)
547 (umax-toc nil)
548 (case-fold-search nil)
549 (bfname (buffer-file-name (or (buffer-base-buffer) (current-buffer))))
550 (filesuffix (or (plist-get export-plist :file-suffix) ".foo"))
551 (filename (concat (file-name-as-directory
552 (org-export-directory :ascii opt-plist))
553 (file-name-sans-extension
554 (or (and subtree-p
555 (org-entry-get (region-beginning)
556 "EXPORT_FILE_NAME" t))
557 (file-name-nondirectory bfname)))
558 filesuffix))
559 (filename (if (equal (file-truename filename)
560 (file-truename bfname))
561 (concat filename filesuffix)
562 filename))
563 (buffer (find-file-noselect filename))
564 (org-levels-open (make-vector org-level-max nil))
565 (odd org-odd-levels-only)
566 (date (plist-get opt-plist :date))
567 (author (plist-get opt-plist :author))
568 (title (or (and subtree-p (org-export-get-title-from-subtree))
569 (plist-get opt-plist :title)
570 (and (not
571 (plist-get opt-plist :skip-before-1st-heading))
572 (org-export-grab-title-from-buffer))
573 (file-name-sans-extension
574 (file-name-nondirectory bfname))))
575 (email (plist-get opt-plist :email))
576 (language (plist-get opt-plist :language))
577 (quote-re0 (concat "^[ \t]*" org-quote-string "\\>"))
578 ; (quote-re (concat "^\\(\\*+\\)\\([ \t]*" org-quote-string "\\>\\)"))
579 (todo nil)
580 (lang-words nil)
581 (region
582 (buffer-substring
583 (if (org-region-active-p) (region-beginning) (point-min))
584 (if (org-region-active-p) (region-end) (point-max))))
585 (lines (org-split-string
586 (org-export-preprocess-string
587 region
588 :for-ascii t
589 :skip-before-1st-heading
590 (plist-get opt-plist :skip-before-1st-heading)
591 :drawers (plist-get export-plist :drawers-export)
592 :tags (plist-get export-plist :tags-export)
593 :priority (plist-get export-plist :priority-export)
594 :footnotes (plist-get export-plist :footnotes-export)
595 :timestamps (plist-get export-plist :timestamps-export)
596 :todo-keywords (plist-get export-plist :todo-keywords-export)
597 :verbatim-multiline t
598 :select-tags (plist-get export-plist :select-tags-export)
599 :exclude-tags (plist-get export-plist :exclude-tags-export)
600 :archived-trees
601 (plist-get export-plist :archived-trees-export)
602 :add-text (plist-get opt-plist :text))
603 "\n"))
604 ;; export-generic plist variables
605 (withtags (plist-get export-plist :tags-export))
606 (tagsintoc (plist-get export-plist :toc-tags-export))
607 (tocnotagsstr (or (plist-get export-plist :toc-tags-none-string) ""))
608 (tocdepth (plist-get export-plist :toc-indent-depth))
609 (tocindentchar (plist-get export-plist :toc-indent-char))
610 (tocsecnums (plist-get export-plist :toc-section-numbers))
611 (tocsecnumform (plist-get export-plist :toc-section-number-format))
612 (tocformat (plist-get export-plist :toc-format))
613 (tocformtodo (plist-get export-plist :toc-format-with-todo))
614 (tocprefix (plist-get export-plist :toc-prefix))
615 (tocsuffix (plist-get export-plist :toc-suffix))
616 (bodyfixedpre (plist-get export-plist :body-line-fixed-prefix))
617 (bodyfixedsuf (plist-get export-plist :body-line-fixed-suffix))
618 (bodyfixedform (or (plist-get export-plist :body-line-fixed-format)
619 "%s"))
620 (listprefix (plist-get export-plist :body-list-prefix))
621 (listsuffix (plist-get export-plist :body-list-suffix))
622 (listformat (or (plist-get export-plist :body-list-format) "%s\n"))
623 (numlistleavenum
624 (plist-get export-plist :body-number-list-leave-number))
625 (numlistprefix (plist-get export-plist :body-number-list-prefix))
626 (numlistsuffix (plist-get export-plist :body-number-list-suffix))
627 (numlistformat
628 (or (plist-get export-plist :body-number-list-format) "%s\n"))
629 (listchecktodo
630 (or (plist-get export-plist :body-list-checkbox-todo) "\\1"))
631 (listcheckdone
632 (or (plist-get export-plist :body-list-checkbox-done) "\\1"))
633 (listcheckhalf
634 (or (plist-get export-plist :body-list-checkbox-half) "\\1"))
635 (listchecktodoend
636 (or (plist-get export-plist :body-list-checkbox-todo-end) ""))
637 (listcheckdoneend
638 (or (plist-get export-plist :body-list-checkbox-done-end) ""))
639 (listcheckhalfend
640 (or (plist-get export-plist :body-list-checkbox-half-end) ""))
641 (bodytextpre (plist-get export-plist :body-text-prefix))
642 (bodytextsuf (plist-get export-plist :body-text-suffix))
643 (bodylinewrap (plist-get export-plist :body-line-wrap))
644 (bodylineform (or (plist-get export-plist :body-line-format) "%s"))
646 thetoc toctags have-headings first-heading-pos
647 table-open table-buffer link-buffer link desc desc0 rpl wrap)
649 (let ((inhibit-read-only t))
650 (org-unmodified
651 (remove-text-properties (point-min) (point-max)
652 '(:org-license-to-kill t))))
654 (setq org-min-level (org-get-min-level lines level-offset))
655 (setq org-last-level org-min-level)
656 (org-init-section-numbers)
658 (find-file-noselect filename)
660 (setq lang-words (or (assoc language org-export-language-setup)
661 (assoc "en" org-export-language-setup)))
662 (switch-to-buffer-other-window buffer)
663 (erase-buffer)
664 (fundamental-mode)
665 ;; create local variables for all options, to make sure all called
666 ;; functions get the correct information
667 (mapc (lambda (x)
668 (set (make-local-variable (nth 2 x))
669 (plist-get opt-plist (car x))))
670 org-export-plist-vars)
671 (org-set-local 'org-odd-levels-only odd)
672 (setq umax (if arg (prefix-numeric-value arg)
673 org-export-headline-levels))
674 (setq umax-toc umax)
676 ;; File header
677 (if title
678 (insert
679 (org-export-generic-header title export-plist
680 :title-prefix
681 :title-format
682 :title-suffix)))
684 (if (and (or author email)
685 (plist-get export-plist :author-export))
686 (insert (concat (nth 1 lang-words) ": " (or author "")
687 (if email (concat " <" email ">") "")
688 "\n")))
690 (cond
691 ((and date (string-match "%" date))
692 (setq date (format-time-string date)))
693 (date)
694 (t (setq date (format-time-string "%Y-%m-%d %T %Z"))))
696 (if (and date (plist-get export-plist :date-export))
697 (insert
698 (org-export-generic-header date export-plist
699 :date-prefix
700 :date-format
701 :date-suffix)))
703 ;; export the table of contents first
704 (if (plist-get export-plist :toc-export)
705 (progn
706 (push
707 (org-export-generic-header (nth 3 lang-words) export-plist
708 :toc-header-prefix
709 :toc-header-format
710 :toc-header-suffix)
711 thetoc)
713 (if tocprefix
714 (push tocprefix thetoc))
716 (mapc '(lambda (line)
717 (if (string-match org-todo-line-regexp line)
718 ;; This is a headline
719 (progn
720 (setq have-headings t)
721 (setq level (- (match-end 1) (match-beginning 1)
722 level-offset)
723 level (org-tr-level level)
724 txt (match-string 3 line)
725 todo
726 (or (and org-export-mark-todo-in-toc
727 (match-beginning 2)
728 (not (member (match-string 2 line)
729 org-done-keywords)))
730 ; TODO, not DONE
731 (and org-export-mark-todo-in-toc
732 (= level umax-toc)
733 (org-search-todo-below
734 line lines level))))
735 (setq txt (org-html-expand-for-generic txt))
737 (while (string-match org-bracket-link-regexp txt)
738 (setq txt
739 (replace-match
740 (match-string (if (match-end 2) 3 1) txt)
741 t t txt)))
743 (if (and (not tagsintoc)
744 (string-match
745 (org-re "[ \t]+:[[:alnum:]_@:]+:[ \t]*$")
746 txt))
747 (setq txt (replace-match "" t t txt))
748 ; include tags but formated
749 (if (string-match
750 (org-re "[ \t]+:\\([[:alnum:]_@:]+\\):[ \t]*$")
751 txt)
752 (progn
753 (setq
754 toctags
755 (org-export-generic-header
756 (match-string 1 txt)
757 export-plist :toc-tags-prefix
758 :toc-tags-format :toc-tags-suffix))
759 (string-match
760 (org-re "[ \t]+:[[:alnum:]_@:]+:[ \t]*$")
761 txt)
762 (setq txt (replace-match "" t t txt)))
763 (setq toctags tocnotagsstr)))
765 (if (string-match quote-re0 txt)
766 (setq txt (replace-match "" t t txt)))
768 (if (<= level umax-toc)
769 (progn
770 (push
771 (concat
773 (make-string
774 (* (max 0 (- level org-min-level)) tocdepth)
775 tocindentchar)
777 (if tocsecnums
778 (format tocsecnumform
779 (org-section-number level))
782 (format
783 (if todo tocformtodo tocformat)
784 txt)
786 toctags)
788 thetoc)
789 (setq org-last-level level))
790 ))))
791 lines)
792 (if tocsuffix
793 (push tocsuffix thetoc))
794 (setq thetoc (if have-headings (nreverse thetoc) nil))))
796 (org-init-section-numbers)
797 (org-export-generic-check-section "top")
798 (while (setq line (pop lines))
799 (when (and link-buffer (string-match "^\\*+ " line))
800 (org-export-generic-push-links (nreverse link-buffer))
801 (setq link-buffer nil))
802 (setq wrap nil)
803 ;; Remove the quoted HTML tags.
804 ;; XXX
805 (setq line (org-html-expand-for-generic line))
806 ;; Replace links with the description when possible
807 ;; XXX
808 (while (string-match org-bracket-link-regexp line)
809 (setq link (match-string 1 line)
810 desc0 (match-string 3 line)
811 desc (or desc0 (match-string 1 line)))
812 (if (and (> (length link) 8)
813 (equal (substring link 0 8) "coderef:"))
814 (setq line (replace-match
815 (format (org-export-get-coderef-format (substring link 8) desc)
816 (cdr (assoc
817 (substring link 8)
818 org-export-code-refs)))
819 t t line))
820 (setq rpl (concat "["
821 (or (match-string 3 line) (match-string 1 line))
822 "]"))
823 (when (and desc0 (not (equal desc0 link)))
824 (if org-export-generic-links-to-notes
825 (push (cons desc0 link) link-buffer)
826 (setq rpl (concat rpl " (" link ")")
827 wrap (+ (length line) (- (length (match-string 0) line))
828 (length desc)))))
829 (setq line (replace-match rpl t t line))))
830 (when custom-times
831 (setq line (org-translate-time line)))
832 (cond
833 ((string-match "^\\(\\*+\\)[ \t]+\\(.*\\)" line)
835 ;; a Headline
837 (org-export-generic-check-section "headline")
839 (setq first-heading-pos (or first-heading-pos (point)))
840 (setq level (org-tr-level (- (match-end 1) (match-beginning 1)
841 level-offset))
842 txt (match-string 2 line))
843 (org-generic-level-start level old-level txt umax export-plist lines)
844 (setq old-level level))
846 ((and org-export-with-tables
847 (string-match "^\\([ \t]*\\)\\(|\\|\\+-+\\+\\)" line))
849 ;; a Table
851 (org-export-generic-check-section "table")
853 (if (not table-open)
854 ;; New table starts
855 (setq table-open t table-buffer nil))
856 ;; Accumulate table lines
857 (setq table-buffer (cons line table-buffer))
858 (when (or (not lines)
859 (not (string-match "^\\([ \t]*\\)\\(|\\|\\+-+\\+\\)"
860 (car lines))))
861 (setq table-open nil
862 table-buffer (nreverse table-buffer))
863 (insert (mapconcat
864 (lambda (x)
865 (org-fix-indentation x org-generic-current-indentation))
866 (org-format-table-generic table-buffer)
867 "\n") "\n")))
869 ((string-match "^\\([ \t]*\\)\\(:\\( \\|$\\)\\)" line)
871 ;; pre-formated text
873 (setq line (replace-match "\\1" nil nil line))
875 (org-export-generic-check-section "preformat" bodyfixedpre bodyfixedsuf)
877 (insert (format bodyfixedform line)))
879 ((string-match "^\\([ \t]+\\)\\([-+*][ \t]*\\)" line)
881 ;; plain list item
883 ;; TODO: nested lists
885 (setq line (replace-match "" nil nil line))
887 (org-export-generic-check-section "liststart" listprefix listsuffix)
889 ;; deal with checkboxes
890 (cond
891 ((string-match "^\\(\\[ \\]\\)[ \t]*" line)
892 (setq line (concat (replace-match listchecktodo nil nil line)
893 listchecktodoend)))
894 ((string-match "^\\(\\[X\\]\\)[ \t]*" line)
895 (setq line (concat (replace-match listcheckdone nil nil line)
896 listcheckdoneend)))
897 ((string-match "^\\(\\[/\\]\\)[ \t]*" line)
898 (setq line (concat (replace-match listcheckhalf nil nil line)
899 listcheckhalfend)))
902 (insert (format listformat line)))
903 ((string-match "^\\([ \t]+\\)\\([0-9]+\\.[ \t]*\\)" line)
905 ;; numbered list item
907 ;; TODO: nested lists
909 (setq line (replace-match (if numlistleavenum "\\2" "") nil nil line))
911 (org-export-generic-check-section "numliststart"
912 numlistprefix numlistsuffix)
914 ;; deal with checkboxes
915 ;; TODO: whoops; leaving the numbers is a problem for ^ matching
916 (cond
917 ((string-match "\\(\\[ \\]\\)[ \t]*" line)
918 (setq line (concat (replace-match listchecktodo nil nil line)
919 listchecktodoend)))
920 ((string-match "\\(\\[X\\]\\)[ \t]*" line)
921 (setq line (concat (replace-match listcheckdone nil nil line)
922 listcheckdoneend)))
923 ((string-match "\\(\\[/\\]\\)[ \t]*" line)
924 (setq line (concat (replace-match listcheckhalf nil nil line)
925 listcheckhalfend)))
928 (insert (format numlistformat line)))
931 ;; body
933 (org-export-generic-check-section "body" bodytextpre bodytextsuf)
935 ;; XXX: properties? list?
936 (if (string-match "^\\([ \t]*\\)\\([-+*][ \t]+\\)\\(.*?\\)\\( ::\\)" line)
937 (setq line (replace-match "\\1\\3:" t nil line)))
939 (setq line (org-fix-indentation line org-generic-current-indentation))
941 ;; Remove forced line breaks
942 (if (string-match "\\\\\\\\[ \t]*$" line)
943 (setq line (replace-match "" t t line)))
945 (if bodylinewrap
946 ;; XXX: was dependent on wrap var which was calculated by???
947 (if (> (length line) bodylinewrap)
948 (setq line
949 (org-export-generic-wrap line bodylinewrap))
950 (setq line line)))
951 (insert (format bodylineform line)))))
953 ;; if we're at a level > 0; insert the closing body level stuff
954 (let ((counter 0))
955 (while (> (- level counter) 0)
956 (insert
957 (org-export-generic-format export-plist :body-section-suffix 0
958 (- level counter)))
959 (setq counter (1+ counter))))
961 (org-export-generic-check-section "bottom")
963 (org-export-generic-push-links (nreverse link-buffer))
965 (normal-mode)
967 ;; insert the table of contents
968 (when thetoc
969 (goto-char (point-min))
970 (if (re-search-forward "^[ \t]*\\[TABLE-OF-CONTENTS\\][ \t]*$" nil t)
971 (progn
972 (goto-char (match-beginning 0))
973 (replace-match ""))
974 (goto-char first-heading-pos))
975 (mapc 'insert thetoc)
976 (or (looking-at "[ \t]*\n[ \t]*\n")
977 (insert "\n\n")))
979 ;; Convert whitespace place holders
980 (goto-char (point-min))
981 (let (beg end)
982 (while (setq beg (next-single-property-change (point) 'org-whitespace))
983 (setq end (next-single-property-change beg 'org-whitespace))
984 (goto-char beg)
985 (delete-region beg end)
986 (insert (make-string (- end beg) ?\ ))))
988 (save-buffer)
990 ;; remove display and invisible chars
991 (let (beg end)
992 (goto-char (point-min))
993 (while (setq beg (next-single-property-change (point) 'display))
994 (setq end (next-single-property-change beg 'display))
995 (delete-region beg end)
996 (goto-char beg)
997 (insert "=>"))
998 (goto-char (point-min))
999 (while (setq beg (next-single-property-change (point) 'org-cwidth))
1000 (setq end (next-single-property-change beg 'org-cwidth))
1001 (delete-region beg end)
1002 (goto-char beg)))
1003 (goto-char (point-min))))
1005 (defun org-export-generic-format (export-plist prop &optional len n reverse)
1006 "converts a property specification to a string given types of properties
1008 The EXPORT-PLIST should be defined as the lookup plist.
1009 The PROP should be the property name to search for in it.
1010 LEN is set to the length of multi-characters strings to generate (or 0)
1011 N is the tree depth
1012 REVERSE means to reverse the list if the plist match is a list
1014 (let* ((prefixtype (plist-get export-plist prop))
1015 subtype)
1016 (cond
1017 ((null prefixtype) "")
1018 ((and len (char-or-string-p prefixtype) (not (stringp prefixtype)))
1019 ;; sequence of chars
1020 (concat (make-string len prefixtype) "\n"))
1021 ((stringp prefixtype)
1022 prefixtype)
1023 ((and n (listp prefixtype))
1024 (if reverse
1025 (setq prefixtype (reverse prefixtype)))
1026 (setq subtype (if (> n (length prefixtype))
1027 (car (last prefixtype))
1028 (nth (1- n) prefixtype)))
1029 (if (stringp subtype)
1030 subtype
1031 (concat (make-string len subtype) "\n")))
1032 (t ""))
1035 (defun org-export-generic-header (header export-plist
1036 prefixprop formatprop postfixprop
1037 &optional n reverse)
1038 "convert a header to an output string given formatting property names"
1039 (let* ((formatspec (plist-get export-plist formatprop))
1040 (len (length header)))
1041 (concat
1042 (org-export-generic-format export-plist prefixprop len n reverse)
1043 (format (or formatspec "%s") header)
1044 (org-export-generic-format export-plist postfixprop len n reverse))
1047 (defun org-export-generic-preprocess (parameters)
1048 "Do extra work for ASCII export"
1049 ;; Put quotes around verbatim text
1050 (goto-char (point-min))
1051 (while (re-search-forward org-verbatim-re nil t)
1052 (goto-char (match-end 2))
1053 (backward-delete-char 1) (insert "'")
1054 (goto-char (match-beginning 2))
1055 (delete-char 1) (insert "`")
1056 (goto-char (match-end 2)))
1057 ;; Remove target markers
1058 (goto-char (point-min))
1059 (while (re-search-forward "<<<?\\([^<>]*\\)>>>?\\([ \t]*\\)" nil t)
1060 (replace-match "\\1\\2")))
1062 (defun org-html-expand-for-generic (line)
1063 "Handle quoted HTML for ASCII export."
1064 (if org-export-html-expand
1065 (while (string-match "@<[^<>\n]*>" line)
1066 ;; We just remove the tags for now.
1067 (setq line (replace-match "" nil nil line))))
1068 line)
1070 (defun org-export-generic-wrap (line where)
1071 "Wrap LINE at or before WHERE."
1072 (let* ((ind (org-get-indentation line))
1073 (indstr (make-string ind ?\ ))
1074 (len (length line))
1075 (result "")
1076 pos didfirst)
1077 (while (> len where)
1078 (catch 'found
1079 (loop for i from where downto (/ where 2) do
1080 (and (equal (aref line i) ?\ )
1081 (setq pos i)
1082 (throw 'found t))))
1083 (if pos
1084 (progn
1085 (setq result
1086 (concat result
1087 (if didfirst indstr "")
1088 (substring line 0 pos)
1089 "\n"))
1090 (setq didfirst t)
1091 (setq line (substring line (1+ pos)))
1092 (setq len (length line)))
1093 (setq result (concat result line))
1094 (setq len 0)))
1095 (concat result indstr line)))
1097 (defun org-export-generic-push-links (link-buffer)
1098 "Push out links in the buffer."
1099 (when link-buffer
1100 ;; We still have links to push out.
1101 (insert "\n")
1102 (let ((ind ""))
1103 (save-match-data
1104 (if (save-excursion
1105 (re-search-backward
1106 "^\\(\\([ \t]*\\)\\|\\(\\*+ \\)\\)[^ \t\n]" nil t))
1107 (setq ind (or (match-string 2)
1108 (make-string (length (match-string 3)) ?\ )))))
1109 (mapc (lambda (x) (insert ind "[" (car x) "]: " (cdr x) "\n"))
1110 link-buffer))
1111 (insert "\n")))
1113 (defun org-generic-level-start (level old-level title umax export-plist
1114 &optional lines)
1115 "Insert a new level in a generic export."
1116 (let ((n (- level umax 1))
1117 (ind 0)
1118 (diff (- level old-level)) (counter 0)
1119 (secnums (plist-get export-plist :body-header-section-numbers))
1120 (secnumformat
1121 (plist-get export-plist :body-header-section-number-format))
1122 char tagstring)
1123 (unless org-export-with-tags
1124 (if (string-match (org-re "[ \t]+\\(:[[:alnum:]_@:]+:\\)[ \t]*$") title)
1125 (setq title (replace-match "" t t title))))
1127 (cond
1128 ;; going deeper
1129 ((> level old-level)
1130 (while (< (+ old-level counter) (1- level))
1131 (insert
1132 (org-export-generic-format export-plist :body-section-prefix 0
1133 (+ old-level counter)))
1134 (setq counter (1+ counter))
1136 ;; going up
1137 ((< level old-level)
1138 (while (> (- old-level counter) (1- level))
1139 (insert
1140 (org-export-generic-format export-plist :body-section-suffix 0
1141 (- old-level counter)))
1142 (setq counter (1+ counter))
1144 ;; same level
1145 ((= level old-level)
1146 (insert
1147 (org-export-generic-format export-plist :body-section-suffix 0 level))
1150 (insert
1151 (org-export-generic-format export-plist :body-section-prefix 0 level))
1153 (if (and org-export-with-section-numbers
1154 secnums
1155 (or (not (numberp secnums))
1156 (< level secnums)))
1157 (setq title
1158 (concat (format (or secnumformat "%s ")
1159 (org-section-number level)) title)))
1161 ;; handle tags and formatting
1162 (if (string-match
1163 (org-re "[ \t]+:\\([[:alnum:]_@:]+\\):[ \t]*$") title)
1164 (progn
1165 (if (plist-get export-plist :body-tags-export)
1166 (setq tagstring (org-export-generic-header (match-string 1 title)
1167 export-plist
1168 :body-tags-prefix
1169 :body-tags-format
1170 :body-tags-suffix)))
1171 (string-match (org-re "[ \t]+:[[:alnum:]_@:]+:[ \t]*$") title)
1172 (setq title (replace-match "" t t title)))
1173 (setq tagstring (plist-get export-plist :body-tags-none-string)))
1175 (insert
1176 (org-export-generic-header title export-plist
1177 :body-section-header-prefix
1178 :body-section-header-format
1179 :body-section-header-suffix
1180 level))
1181 (if tagstring
1182 (insert tagstring))
1184 (setq org-generic-current-indentation '(0 . 0))))
1186 (defun org-insert-centered (s &optional underline)
1187 "Insert the string S centered and underline it with character UNDERLINE."
1188 (let ((ind (max (/ (- fill-column (string-width s)) 2) 0)))
1189 (insert (make-string ind ?\ ) s "\n")
1190 (if underline
1191 (insert (make-string ind ?\ )
1192 (make-string (string-width s) underline)
1193 "\n"))))
1195 (defvar org-table-colgroup-info nil)
1196 (defun org-format-table-generic (lines)
1197 "Format a table for ascii export."
1198 (if (stringp lines)
1199 (setq lines (org-split-string lines "\n")))
1200 (if (not (string-match "^[ \t]*|" (car lines)))
1201 ;; Table made by table.el - test for spanning
1202 lines
1204 ;; A normal org table
1205 ;; Get rid of hlines at beginning and end
1206 (if (string-match "^[ \t]*|-" (car lines)) (setq lines (cdr lines)))
1207 (setq lines (nreverse lines))
1208 (if (string-match "^[ \t]*|-" (car lines)) (setq lines (cdr lines)))
1209 (setq lines (nreverse lines))
1210 (when org-export-table-remove-special-lines
1211 ;; Check if the table has a marking column. If yes remove the
1212 ;; column and the special lines
1213 (setq lines (org-table-clean-before-export lines)))
1214 ;; Get rid of the vertical lines except for grouping
1215 (let ((vl (org-colgroup-info-to-vline-list org-table-colgroup-info))
1216 rtn line vl1 start)
1217 (while (setq line (pop lines))
1218 (if (string-match org-table-hline-regexp line)
1219 (and (string-match "|\\(.*\\)|" line)
1220 (setq line (replace-match " \\1" t nil line)))
1221 (setq start 0 vl1 vl)
1222 (while (string-match "|" line start)
1223 (setq start (match-end 0))
1224 (or (pop vl1) (setq line (replace-match " " t t line)))))
1225 (push line rtn))
1226 (nreverse rtn))))
1228 (defun org-colgroup-info-to-vline-list (info)
1229 (let (vl new last)
1230 (while info
1231 (setq last new new (pop info))
1232 (if (or (memq last '(:end :startend))
1233 (memq new '(:start :startend)))
1234 (push t vl)
1235 (push nil vl)))
1236 (setq vl (nreverse vl))
1237 (and vl (setcar vl nil))
1238 vl))
1240 (provide 'org-generic)
1242 ;;; org-export-generic.el ends here