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
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 ;; ----------------------------------------------------------------------
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"
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"
51 ;; Note: Upper case key-bindings are reserved for your use. Lower
52 ;; case key bindings may conflict with future export-generic
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
60 ;; ----------------------------------------------------------------------
63 ;; * handle function references
64 ;; * handle other types of multi-complex-listy-things to do
65 ;; ideas: (t ?- "%s" ?-)
66 ;; * handle indent specifiers better
68 ;; * need flag to remove indents from body text
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
86 ;; *** supported now, but need separate format per tag
87 ;; *** allow different open/closing prefixes
91 ;; * optmization (many plist extracts should be in (let) vars
92 ;; * define defcustom spec for the specifier list
94 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
101 (defgroup org-export-generic nil
102 "Options specific for ASCII export of Org-mode files."
103 :tag
"Org Export ASCII"
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
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)
127 :header-prefix
"<header>\n"
128 :header-suffix
"</header>\n"
137 :title-format
"<h1>%s</h1>\n"
141 :date-prefix
"<date>"
142 :date-format
"<br /><b>Date:</b> <i>%s</i><br />"
143 :date-suffix
"</date>\n\n"
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) "
156 :toc-format-with-todo
"!!%s!!\n"
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")
180 :todo-keywords-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)>"
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"
232 ;; (close to the original ascii specifier)
247 :date-format
"Date: %s\n"
250 :toc-header-prefix
""
251 :toc-header-format
"%s\n"
252 :toc-header-suffix ?
=
255 :toc-section-numbers t
256 :toc-section-number-format
"%s "
258 :toc-format-with-todo
"%s (*)\n"
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"
281 ; :body-text-prefix "<t>\n"
282 ; :body-text-suffix "</t>\n"
285 :body-bullet-list-prefix
(?
* ?
+ ?-
)
286 ; :body-bullet-list-suffix (?* ?+ ?-)
299 :title-format
"= %s =\n"
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"
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
329 ;; simple html output
333 :header-prefix
"<body>"
335 :title-format
"<h1>%s</h1>\n\n"
338 :date-format
"<br /><b>Date:</b> <i>%s</i><br />\n\n"
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
369 ;; this tries to use every specifier for demo purposes
373 :title-prefix
"<?xml version=\"1.0\"\?>
374 <!DOCTYPE rfc SYSTEM \"rfc2629.dtd\" [
375 <!ENTITY rfcs PUBLIC '' 'blah'>
376 <?rfc strict=\"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\">
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>
400 <date month=\"FILLMONTH\" year=\"FILLYEAR\"/>
401 <area>Operations and Management</area>
402 <workgroup>FIXME</workgroup>
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"
419 :body-line-format
"%s"
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
"")
441 (defun org-set-generic-type (type definition
)
442 "Adds a TYPE and DEFINITION to the existing list of defined generic
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
)
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
)
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."
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)))
484 (and (org-at-heading-p)
485 (>= (org-end-of-subtree t t
) rend
)))))
486 (level-offset (if subtree-p
489 (+ (funcall outline-level
)
490 (if org-odd-levels-only
1 0)))
492 (opt-plist (setq org-export-opt-plist
494 (org-export-add-subtree-options opt-plist rbeg
)
498 (bogus (mapc (lambda (x)
500 (concat helpstart
"\["
502 (plist-get (cdr x
) :key-binding
))
506 (help (concat helpstart
"
508 \[ ] the current setting of the org-generic-export-type variable
516 (plist-get (cdr x
) :key-binding
)
519 (list (list ?
"default"))))
523 ;; read in the type to use
527 (save-window-excursion
528 (delete-other-windows)
529 (with-output-to-temp-buffer "*Org Export/Generic Styles 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
))
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
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
555 (org-entry-get (region-beginning)
556 "EXPORT_FILE_NAME" t
))
557 (file-name-nondirectory bfname
)))
559 (filename (if (equal (file-truename filename
)
560 (file-truename bfname
))
561 (concat filename filesuffix
)
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
)
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 "\\>\\)"))
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
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
)
601 (plist-get export-plist
:archived-trees-export
)
602 :add-text
(plist-get opt-plist
:text
))
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
)
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"))
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
))
628 (or (plist-get export-plist
:body-number-list-format
) "%s\n"))
630 (or (plist-get export-plist
:body-list-checkbox-todo
) "\\1"))
632 (or (plist-get export-plist
:body-list-checkbox-done
) "\\1"))
634 (or (plist-get export-plist
:body-list-checkbox-half
) "\\1"))
636 (or (plist-get export-plist
:body-list-checkbox-todo-end
) ""))
638 (or (plist-get export-plist
:body-list-checkbox-done-end
) ""))
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
))
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
)
665 ;; create local variables for all options, to make sure all called
666 ;; functions get the correct information
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
))
679 (org-export-generic-header title export-plist
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
">") "")
691 ((and date
(string-match "%" date
))
692 (setq date
(format-time-string date
)))
694 (t (setq date
(format-time-string "%Y-%m-%d %T %Z"))))
696 (if (and date
(plist-get export-plist
:date-export
))
698 (org-export-generic-header date export-plist
703 ;; export the table of contents first
704 (if (plist-get export-plist
:toc-export
)
707 (org-export-generic-header (nth 3 lang-words
) export-plist
714 (push tocprefix thetoc
))
716 (mapc '(lambda (line)
717 (if (string-match org-todo-line-regexp line
)
718 ;; This is a headline
720 (setq have-headings t
)
721 (setq level
(- (match-end 1) (match-beginning 1)
723 level
(org-tr-level level
)
724 txt
(match-string 3 line
)
726 (or (and org-export-mark-todo-in-toc
728 (not (member (match-string 2 line
)
731 (and org-export-mark-todo-in-toc
733 (org-search-todo-below
735 (setq txt
(org-html-expand-for-generic txt
))
737 (while (string-match org-bracket-link-regexp txt
)
740 (match-string (if (match-end 2) 3 1) txt
)
743 (if (and (not tagsintoc
)
745 (org-re "[ \t]+:[[:alnum:]_@:]+:[ \t]*$")
747 (setq txt
(replace-match "" t t txt
))
748 ; include tags but formated
750 (org-re "[ \t]+:\\([[:alnum:]_@:]+\\):[ \t]*$")
755 (org-export-generic-header
757 export-plist
:toc-tags-prefix
758 :toc-tags-format
:toc-tags-suffix
))
760 (org-re "[ \t]+:[[:alnum:]_@:]+:[ \t]*$")
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
)
774 (* (max 0 (- level org-min-level
)) tocdepth
)
778 (format tocsecnumform
779 (org-section-number level
))
783 (if todo tocformtodo tocformat
)
789 (setq org-last-level level
))
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
))
803 ;; Remove the quoted HTML tags.
805 (setq line
(org-html-expand-for-generic line
))
806 ;; Replace links with the description when possible
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
)
818 org-export-code-refs
)))
820 (setq rpl
(concat "["
821 (or (match-string 3 line
) (match-string 1 line
))
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
))
829 (setq line
(replace-match rpl t t line
))))
831 (setq line
(org-translate-time line
)))
833 ((string-match "^\\(\\*+\\)[ \t]+\\(.*\\)" line
)
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)
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
))
851 (org-export-generic-check-section "table")
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]*\\)\\(|\\|\\+-+\\+\\)"
862 table-buffer
(nreverse table-buffer
))
865 (org-fix-indentation x org-generic-current-indentation
))
866 (org-format-table-generic table-buffer
)
869 ((string-match "^\\([ \t]*\\)\\(:\\( \\|$\\)\\)" line
)
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
)
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
891 ((string-match "^\\(\\[ \\]\\)[ \t]*" line
)
892 (setq line
(concat (replace-match listchecktodo nil nil line
)
894 ((string-match "^\\(\\[X\\]\\)[ \t]*" line
)
895 (setq line
(concat (replace-match listcheckdone nil nil line
)
897 ((string-match "^\\(\\[/\\]\\)[ \t]*" line
)
898 (setq line
(concat (replace-match listcheckhalf nil nil line
)
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
917 ((string-match "\\(\\[ \\]\\)[ \t]*" line
)
918 (setq line
(concat (replace-match listchecktodo nil nil line
)
920 ((string-match "\\(\\[X\\]\\)[ \t]*" line
)
921 (setq line
(concat (replace-match listcheckdone nil nil line
)
923 ((string-match "\\(\\[/\\]\\)[ \t]*" line
)
924 (setq line
(concat (replace-match listcheckhalf nil nil line
)
928 (insert (format numlistformat line
)))
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
)))
946 ;; XXX: was dependent on wrap var which was calculated by???
947 (if (> (length line
) bodylinewrap
)
949 (org-export-generic-wrap line bodylinewrap
))
951 (insert (format bodylineform line
)))))
953 ;; if we're at a level > 0; insert the closing body level stuff
955 (while (> (- level counter
) 0)
957 (org-export-generic-format export-plist
:body-section-suffix
0
959 (setq counter
(1+ counter
))))
961 (org-export-generic-check-section "bottom")
963 (org-export-generic-push-links (nreverse link-buffer
))
967 ;; insert the table of contents
969 (goto-char (point-min))
970 (if (re-search-forward "^[ \t]*\\[TABLE-OF-CONTENTS\\][ \t]*$" nil t
)
972 (goto-char (match-beginning 0))
974 (goto-char first-heading-pos
))
975 (mapc 'insert thetoc
)
976 (or (looking-at "[ \t]*\n[ \t]*\n")
979 ;; Convert whitespace place holders
980 (goto-char (point-min))
982 (while (setq beg
(next-single-property-change (point) 'org-whitespace
))
983 (setq end
(next-single-property-change beg
'org-whitespace
))
985 (delete-region beg end
)
986 (insert (make-string (- end beg
) ?\
))))
990 ;; remove display and invisible chars
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
)
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
)
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)
1012 REVERSE means to reverse the list if the plist match is a list
1014 (let* ((prefixtype (plist-get export-plist prop
))
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
)
1023 ((and n
(listp prefixtype
))
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
)
1031 (concat (make-string len subtype
) "\n")))
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
)))
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
))))
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 ?\
))
1077 (while (> len where
)
1079 (loop for i from where downto
(/ where
2) do
1080 (and (equal (aref line i
) ?\
)
1087 (if didfirst indstr
"")
1088 (substring line
0 pos
)
1091 (setq line
(substring line
(1+ pos
)))
1092 (setq len
(length line
)))
1093 (setq result
(concat result line
))
1095 (concat result indstr line
)))
1097 (defun org-export-generic-push-links (link-buffer)
1098 "Push out links in the buffer."
1100 ;; We still have links to push out.
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"))
1113 (defun org-generic-level-start (level old-level title umax export-plist
1115 "Insert a new level in a generic export."
1116 (let ((n (- level umax
1))
1118 (diff (- level old-level
)) (counter 0)
1119 (secnums (plist-get export-plist
:body-header-section-numbers
))
1121 (plist-get export-plist
:body-header-section-number-format
))
1123 (unless org-export-with-tags
1124 (if (string-match (org-re "[ \t]+\\(:[[:alnum:]_@:]+:\\)[ \t]*$") title
)
1125 (setq title
(replace-match "" t t title
))))
1129 ((> level old-level
)
1130 (while (< (+ old-level counter
) (1- level
))
1132 (org-export-generic-format export-plist
:body-section-prefix
0
1133 (+ old-level counter
)))
1134 (setq counter
(1+ counter
))
1137 ((< level old-level
)
1138 (while (> (- old-level counter
) (1- level
))
1140 (org-export-generic-format export-plist
:body-section-suffix
0
1141 (- old-level counter
)))
1142 (setq counter
(1+ counter
))
1145 ((= level old-level
)
1147 (org-export-generic-format export-plist
:body-section-suffix
0 level
))
1151 (org-export-generic-format export-plist
:body-section-prefix
0 level
))
1153 (if (and org-export-with-section-numbers
1155 (or (not (numberp secnums
))
1158 (concat (format (or secnumformat
"%s ")
1159 (org-section-number level
)) title
)))
1161 ;; handle tags and formatting
1163 (org-re "[ \t]+:\\([[:alnum:]_@:]+\\):[ \t]*$") title
)
1165 (if (plist-get export-plist
:body-tags-export
)
1166 (setq tagstring
(org-export-generic-header (match-string 1 title
)
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
)))
1176 (org-export-generic-header title export-plist
1177 :body-section-header-prefix
1178 :body-section-header-format
1179 :body-section-header-suffix
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")
1191 (insert (make-string ind ?\
)
1192 (make-string (string-width s
) underline
)
1195 (defvar org-table-colgroup-info nil
)
1196 (defun org-format-table-generic (lines)
1197 "Format a table for ascii export."
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
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
))
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
)))))
1228 (defun org-colgroup-info-to-vline-list (info)
1231 (setq last new new
(pop info
))
1232 (if (or (memq last
'(:end
:startend
))
1233 (memq new
'(:start
:startend
)))
1236 (setq vl
(nreverse vl
))
1237 (and vl
(setcar vl nil
))
1240 (provide 'org-generic
)
1242 ;;; org-export-generic.el ends here