Merged from mwolson@gnu.org--2006 (patch 36-37)
[planner-el.git] / planner-publish.el
blobcbcd01f3c6d38bdc1b93acc958448cc145b24f2e
1 ;;; planner-publish.el --- planner-specific publishing
3 ;; Copyright (C) 2005, 2006 Peter K. Lee
4 ;; Parts copyright (C) 2005 Chris McMahan
5 ;; Parts copyright (C) 2005, 2006 Free Software Foundation, Inc.
6 ;; Parts copyright (C) 2005 Dale P. Smith
8 ;; Author: Peter K. Lee <saint@ c o r e n o v a .com>
9 ;; Keywords: planner publish
10 ;; Timestamp: 20 Jul 2005 10:05:29
11 ;; X-URL: http://www.corenova.com/...
13 ;; This file is part of Planner. It is not part of GNU Emacs.
15 ;; Planner is free software; you can redistribute it and/or modify it
16 ;; under the terms of the GNU General Public License as published by
17 ;; the Free Software Foundation; either version 2, or (at your option)
18 ;; any later version.
20 ;; Planner is distributed in the hope that it will be useful, but
21 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
22 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 ;; General Public License for more details.
25 ;; You should have received a copy of the GNU General Public License
26 ;; along with Planner; see the file COPYING. If not, write to the
27 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
28 ;; Boston, MA 02110-1301, USA.
30 ;;; Commentary:
32 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
34 ;;; Introduction
36 ;; Muse Styles for Planner: planner-xml, planner-html, planner-xhtml, etc.
38 ;; Handles publishing of planner files. Works with Muse to generate
39 ;; flexible markup.
41 ;;; History:
43 ;; 2005-07-15 (0.1) : creation date
44 ;; 2005-07-20 (0.2) : first public release
45 ;; 2005-07-21 (0.3) : added planner-html-style-sheet customize option
46 ;; 2005-08-09 : added to Planner, see ChangeLog for further changes
48 ;;; TODO:
50 ;; add support for various PLANNER specific sections such as Diary,
51 ;; Accomplishments, Timeclock, etc.
53 ;;; Contributors:
55 ;; Chris McMahan (cmcmahan AT one.net) helped notes to publish correctly.
57 ;; Jim Ottaway fixed several bugs.
59 ;; David Smith fixed a few bugs.
61 ;; Dale Smith implemented a new version of the "notes" tag and
62 ;; provided several patches.
64 ;; Andrew J. Korty enabled multiple links with the "categories"
65 ;; attribute.
67 (require 'planner)
69 (require 'muse-mode)
70 (require 'muse-publish)
71 (require 'muse-html) ;;; allow derive style from "html" and "xhtml"
72 (require 'muse-xml) ;;; allow derive style from "xml"
74 (defgroup planner-publish nil
75 "Options controlling the behavior of PLANNER publishing.
76 See `planner-publish' for more information."
77 :group 'planner)
79 (defcustom planner-publish-markup-regexps
80 '((1275 "^#\\([A-C]\\)\\([0-9]*\\)\\s-*\\([_oXDCP]\\)\\s-*\\(.+\\)" 0 task)
81 (1280 "^\\.#[0-9]+\\s-*" 0 note)
82 (3200 planner-date-regexp 0 link))
83 "List of markup rules for publishing PLANNER.
84 For more on the structure of this list, see `muse-publish-markup-regexps'."
85 :type '(repeat (choice
86 (list :tag "Markup rule"
87 integer
88 (choice regexp symbol)
89 integer
90 (choice string function symbol))
91 function))
92 :group 'muse-html)
94 (defcustom planner-publish-markup-functions
95 '((task . planner-publish-markup-task)
96 (note . planner-publish-markup-note))
97 "An alist of style types to custom functions for that kind of text.
98 For more on the structure of this list, see
99 `muse-publish-markup-functions'."
100 :type '(alist :key-type symbol :value-type function)
101 :group 'planner-publish)
103 (defcustom planner-publish-markup-tags
104 '(("nested-section" t nil planner-publish-nested-section-tag)
105 ("title" t t planner-publish-title-tag)
106 ("content" t nil planner-publish-content-tag)
107 ("tasks-section" t nil planner-publish-tasks-section-tag)
108 ("notes-section" t nil planner-publish-notes-section-tag)
109 ("notes" nil nil planner-publish-notes-tag)
110 ("past-notes" nil t planner-publish-past-notes-tag)
111 ("task" t t planner-publish-task-tag)
112 ("note" t t planner-publish-note-tag))
113 "A list of tag specifications, for specially marking up PLANNER.
114 See `muse-publish-markup-tags' for more information."
115 :type '(repeat (list (string :tag "Markup tag")
116 (boolean :tag "Expect closing tag" :value t)
117 (boolean :tag "Parse attributes" :value nil)
118 function))
119 :group 'planner-publish)
121 ;;;_ + XML specific customizations
123 (defcustom planner-xml-markup-strings
124 '((planner-begin-nested-section . "<section>")
125 (planner-end-nested-section . "</section>")
126 (planner-begin-title . "<title>")
127 (planner-end-title . "</title>")
128 (planner-begin-content . "")
129 (planner-end-content . "")
130 (planner-begin-body . "")
131 (planner-end-body . "")
132 (planner-begin-task-section . "<tasks>")
133 (planner-end-task-section . "</tasks>")
134 (planner-begin-task-body . "")
135 (planner-end-task-body . "")
136 (planner-begin-note-section . "<notes>")
137 (planner-end-note-section . "</notes>")
138 (planner-begin-task . "<task status=\"%s\" priority=\"%s\">")
139 (planner-end-task . "</task>")
140 (planner-begin-note . "<note number=\"%s\">")
141 (planner-end-note . "</note>")
142 (planner-begin-note-details . "<details><timestamp>%s</timestamp>")
143 (planner-end-note-details . "</details>")
144 (planner-begin-note-link . "<references>")
145 (planner-end-note-link . "</references>")
146 (planner-begin-note-categories . "<categories>")
147 (planner-end-note-categories . "</categories>"))
148 "Strings used for marking up text as XML.
149 These cover the most basic kinds of markup, the handling of which
150 differs little between the various styles.
152 If a markup rule is not found here, `muse-xml-markup-strings' is
153 searched."
154 :type '(alist :key-type symbol :value-type string)
155 :group 'planner-publish)
157 (defcustom planner-xml-header
158 "<?xml version=\"1.0\" encoding=\"<lisp>(muse-xml-encoding)</lisp>\"?>
159 <PLANNER>
160 <pageinfo>
161 <title><lisp>(muse-publishing-directive \"title\")</lisp></title>
162 <author><lisp>(muse-publishing-directive \"author\")</lisp></author>
163 <maintainer><lisp>(muse-style-element :maintainer)</lisp></maintainer>
164 <pubdate><lisp>(muse-publishing-directive \"date\")</lisp></pubdate>
165 </pageinfo>
166 <!-- Page published by Emacs Muse begins here -->\n"
167 "Header used for publishing PLANNER XML files.
168 This may be text or a filename."
169 :type 'string
170 :group 'planner-publish)
172 (defcustom planner-xml-footer "
173 <!-- Page published by Emacs Muse ends here -->
174 </PLANNER>\n"
175 "Footer used for publishing PLANNER XML files.
176 This may be text or a filename."
177 :type 'string
178 :group 'planner-publish)
180 ;;;_ + HTML specific customizations
182 (defcustom planner-html-markup-strings
183 '((planner-begin-nested-section . "<div class=\"section\">")
184 (planner-end-nested-section . "</div>")
185 (planner-begin-title . "<h%s>")
186 (planner-end-title . "</h%s>")
187 (planner-begin-content . "<div class=\"content\">")
188 (planner-end-content . "</div>")
189 (planner-begin-body . "<div class=\"body\">")
190 (planner-end-body . "</div>")
191 (planner-begin-task-section . "<div id=\"tasks\" class=\"section\">")
192 (planner-end-task-section . "</div>")
193 (planner-begin-task-body . "<ul class=\"body\">")
194 (planner-end-task-body . "</ul>")
195 (planner-begin-note-section . "<div id=\"notes\" class=\"section\">")
196 (planner-end-note-section . "</div>")
197 (planner-begin-task . "<li class=\"task\"><span class=\"%s\"><span class=\"%s\">%s</span>")
198 (planner-end-task . "</span></li>")
199 (planner-begin-note . "<div class=\"note\"><a name=\"%s\"></a><span class=\"anchor\">%s</span>")
200 (planner-end-note . "</div>")
201 (planner-begin-note-details . "<div class=\"details\"><span class=\"timestamp\">%s</span>")
202 (planner-end-note-details . "</div>")
203 (planner-begin-note-link . " <span class=\"link\">")
204 (planner-end-note-link . "</span>")
205 (planner-begin-note-categories . " <span class=\"categories\">")
206 (planner-end-note-categories . "</span>"))
207 "Strings used for marking up text as HTML.
208 These cover the most basic kinds of markup, the handling of which
209 differs little between the various styles.
211 If a markup rule is not found here, `muse-html-markup-strings' is
212 searched."
213 :type '(alist :key-type symbol :value-type string)
214 :group 'planner-publish)
216 (defcustom planner-html-style-sheet
217 "<style type=\"text/css\">
218 body {
219 background: white; color: black;
220 margin-left: 3%; margin-right: 3%;
223 p { margin-top: 3px; margin-bottom: 3px; }
224 p.verse { margin-left: 3% }
226 h1,h2,h3,h4,h5 { margin:0; padding:0; }
228 h1 { padding: 10px; margin-bottom: 10px; }
230 table.muse-table { margin: 0; font-size: 11px;
231 border-collapse: collapse;
232 background: #e2effa;
233 border: 1px solid #aadeed; }
235 table.muse-table tbody td { border: 1px solid #ccdeed; }
237 .example { margin-left: 5px; padding: 3px;
238 background: #fffffc;
239 border: 1px solid #ccdeed; }
241 /* nested sections */
242 .section { margin: 0; padding: 10px;
243 margin-bottom: 15px;
244 font-size: 12px; }
246 .section .section { margin: 0; margin-left: 5px;
247 font-size: 11px; }
249 .title { margin: 0; padding; 0 }
251 /* Tasks section */
252 .task .A { color: red }
253 .task .B { color: green }
254 .task .C { color: navy }
255 .task .done { color: gray; text-decoration: line-through; }
256 .task .cancelled { color: gray; text-decoration: italic; }
258 </style>"
259 "Store your stylesheet definitions here. The provided default
260 is for reference only. You definitely want to customize this for
261 your particular needs & wants. This is used in
262 `planner-html-header' and `planner-xhtml-header'. Refer to
263 `muse-html-style-sheet' for details on usage. You may simply
264 override the above by specifying an explicit link to a CSS file."
265 :type 'string
266 :group 'planner-publish)
268 (defcustom planner-html-header
269 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">
270 <html>
271 <head>
272 <title><lisp>
273 (concat (muse-publishing-directive \"title\")
274 (let ((author (muse-publishing-directive \"author\")))
275 (if (not (string= author (user-full-name)))
276 (concat \" (by \" author \")\"))))</lisp></title>
277 <meta name=\"generator\" content=\"muse.el\">
278 <meta http-equiv=\"<lisp>muse-html-meta-http-equiv</lisp>\"
279 content=\"<lisp>muse-html-meta-content-type</lisp>\">
280 <lisp>
281 (let ((maintainer (muse-style-element :maintainer)))
282 (when maintainer
283 (concat \"<link rev=\\\"made\\\" href=\\\"\" maintainer \"\\\">\")))
284 </lisp>
285 <lisp>planner-html-style-sheet</lisp>
286 </head>
287 <body>
288 <div id=\"content\">
289 <h1><span><lisp>
290 (concat (muse-publishing-directive \"title\")
291 (let ((author (muse-publishing-directive \"author\")))
292 (if (not (string= author (user-full-name)))
293 (concat \" (by \" author \")\"))))</lisp></span></h1>
294 <div id=\"inner-header\">
295 <lisp>planner-html-inner-header</lisp>
296 </div>
297 <div id=\"muse-sections\">
298 <!-- Page published by Emacs Muse begins here -->\n"
299 "Header used for publishing PLANNER HTML files.
300 This may be text or a filename."
301 :type 'string
302 :group 'planner-publish)
304 (defcustom planner-html-footer "
305 <!-- Page published by Emacs Muse ends here -->
306 </div>
307 <div id=\"inner-footer\">
308 <lisp>planner-html-inner-footer</lisp>
309 </div>
310 </div>
311 </body>
312 </html>\n"
313 "Footer used for publishing PLANNER HTML files.
314 This may be text or a filename."
315 :type 'string
316 :group 'planner-publish)
318 (defcustom planner-xhtml-header
319 "<?xml version=\"1.0\" encoding=\"<lisp>
320 (muse-html-encoding)</lisp>\"?>
321 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
322 \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
323 <html xmlns=\"http://www.w3.org/1999/xhtml\">
324 <head>
325 <title><lisp>
326 (concat (muse-publishing-directive \"title\")
327 (let ((author (muse-publishing-directive \"author\")))
328 (if (not (string= author (user-full-name)))
329 (concat \" (by \" author \")\"))))</lisp></title>
330 <meta name=\"generator\" content=\"muse.el\" />
331 <meta http-equiv=\"<lisp>muse-html-meta-http-equiv</lisp>\"
332 content=\"<lisp>muse-html-meta-content-type</lisp>\" />
333 <lisp>
334 (let ((maintainer (muse-style-element :maintainer)))
335 (when maintainer
336 (concat \"<link rev=\\\"made\\\" href=\\\"\" maintainer \"\\\" />\")))
337 </lisp>
338 <lisp>planner-html-style-sheet</lisp>
339 </head>
340 <body>
341 <div id=\"content\">
342 <h1><span><lisp>
343 (concat (muse-publishing-directive \"title\")
344 (let ((author (muse-publishing-directive \"author\")))
345 (if (not (string= author (user-full-name)))
346 (concat \" (by \" author \")\"))))</lisp></span></h1>
347 <div id=\"inner-header\">
348 <lisp>planner-html-inner-header</lisp>
349 </div>
350 <div id=\"muse-sections\">
351 <!-- Page published by Emacs Muse begins here -->\n"
352 "Header used for publishing PLANNER XHTML files.
353 This may be text or a filename."
354 :type 'string
355 :group 'planner-publish)
357 (defcustom planner-xhtml-footer "
358 <!-- Page published by Emacs Muse ends here -->
359 </div>
360 <div id=\"inner-footer\">
361 <lisp>planner-html-inner-footer</lisp>
362 </div>
363 </div>
364 </body>
365 </html>\n"
366 "Footer used for publishing PLANNER XHTML files.
367 This may be text or a filename."
368 :type 'string
369 :group 'planner-publish)
371 (defcustom planner-html-inner-header ""
372 "Extra header section that can be embedded w/in existing
373 `planner-html-header'. This may be text or a filename."
374 :type 'string
375 :group 'planner-publish)
377 (defcustom planner-html-inner-footer ""
378 "Extra footer section that can be embedded w/in existing
379 `planner-html-footer'. This may be text or a filename."
380 :type 'string
381 :group 'planner-publish)
383 ;;;_ + Publishing hooks
385 (defcustom planner-publish-prepare-regexps
386 '((100 "^\\(\\*+\\)\\s-+" 0 planner-publish-section))
387 "List of markup rules to apply before publishing a page with Planner.
388 See `muse-publish-markup-regexps' for details on the syntax used."
389 :type '(repeat (choice
390 (list :tag "Markup rule"
391 integer
392 (choice regexp symbol)
393 integer
394 (choice string function symbol))
395 function))
396 :group 'planner-publish)
398 (defcustom planner-publish-finalize-regexps
400 "List of markup rules to apply after publishing a page with Planner.
401 See `muse-publish-markup-regexps' for details on the syntax used."
402 :type '(repeat (choice
403 (list :tag "Markup rule"
404 integer
405 (choice regexp symbol)
406 integer
407 (choice string function symbol))
408 function))
409 :group 'planner-publish)
411 (defun planner-publish-prepare-buffer ()
412 (goto-char (point-min))
413 (muse-publish-markup "preparing Planner page"
414 planner-publish-prepare-regexps)
415 ;; indicate that we are to continue preparing the buffer
416 nil)
418 (defun planner-publish-finalize-buffer ()
419 (goto-char (point-min))
420 (muse-publish-markup "finalizing Planner page"
421 planner-publish-finalize-regexps)
422 ;; indicate that we are to continue finalizing the buffer
423 nil)
425 ;;;_ + Markup
427 (defun planner-publish-markup-task ()
428 "Replace tasks with XML representation of task data."
429 (save-restriction
430 (narrow-to-region
431 (planner-line-beginning-position)
432 (planner-line-end-position))
433 (muse-publish-escape-specials (point-min) (point-max))
434 (let ((info (planner-current-task-info)))
435 (delete-region (point-min) (point-max))
436 (forward-line 1)
437 (insert
438 (format (concat "<task id=\"%s\" priority=\"%s\" status=\"%s\""
439 " link=\"%s\" plan=\"%s\" date=\"%s\">")
440 (or (planner-task-number info) "")
441 (or (planner-task-priority info) "")
442 (or (planner-publish-task-status-expand
443 (planner-task-status info)) "")
444 (or (planner-task-link-text info) "")
445 (or (planner-task-plan info) "")
446 (or (planner-task-date info) ""))
447 (planner-task-description info) ; mark this area read only
448 "</task>"))))
450 (defun planner-publish-markup-note ()
451 "Replace note with XML representation of note data. Borrowed
452 heavily from Sacha's personal configs."
453 (save-restriction
454 (narrow-to-region
455 (save-excursion (beginning-of-line) (point))
456 (or (save-excursion
457 (and (re-search-forward "^\\(\\.#\\|* \\|</notes-section>\\)" nil t)
458 (match-beginning 0)))
459 (point-max)))
460 (let ((info (planner-current-note-info t)))
461 (delete-region (point-min) (point-max))
462 (insert (format (concat "<note anchor=\"%s\" timestamp=\"%s\""
463 " link=\"%s\" categories=\"%s\">")
464 (planner-note-anchor info)
465 (or (planner-note-timestamp info) "")
466 (or (planner-note-link info) "")
467 (or (planner-note-link-text info) ""))
468 "<title level=\"3\">" (planner-note-title info) "</title>\n"
469 "<content>\n" (planner-note-body info) "\n\n</content>\n"
470 "</note>\n"))))
473 ;;;_ + Tags
475 (defun planner-insert-markup (&rest args)
476 (if (fboundp 'muse-insert-markup)
477 (apply 'muse-insert-markup args)
478 (apply 'insert args)))
480 (defun planner-publish-nested-section-tag (beg end)
481 "Generated by `planner-publish-section', the nested section tag
482 now takes in TITLE and LEVEL attributes.
484 This is related to the Muse concept of sections, but done before
485 marking up the buffer, and with special actions done on the title
486 of each section."
487 (save-excursion
488 (goto-char beg)
489 (planner-insert-markup (muse-markup-text 'planner-begin-nested-section))
490 (goto-char end)
491 (planner-insert-markup (muse-markup-text 'planner-end-nested-section))))
493 (defun planner-publish-title-tag (beg end attrs)
494 (let ((level (cdr (assoc "level" attrs))))
495 (save-excursion
496 (goto-char beg)
497 (planner-insert-markup (muse-markup-text 'planner-begin-title level))
498 (goto-char end)
499 (planner-insert-markup (muse-markup-text 'planner-end-title level)))))
501 (defun planner-publish-content-tag (beg end)
502 (save-excursion
503 (goto-char end)
504 (planner-insert-markup (muse-markup-text 'planner-end-content))
505 (goto-char beg)
506 (planner-insert-markup (muse-markup-text 'planner-begin-content))))
508 (defun planner-publish-tasks-section-tag (beg end)
509 (save-excursion
510 (goto-char beg)
511 (planner-insert-markup (muse-markup-text 'planner-begin-task-section))
512 (forward-line 1)
513 (planner-insert-markup (muse-markup-text 'planner-begin-task-body))
514 (goto-char end)
515 (planner-insert-markup (muse-markup-text 'planner-end-task-body))
516 (planner-insert-markup (muse-markup-text 'planner-end-task-section))))
518 (defun planner-publish-task-tag (beg end attrs)
519 (save-excursion
520 (let ((number (cdr (assoc "id" attrs)))
521 (status (cdr (assoc "status" attrs)))
522 (priority (cdr (assoc "priority" attrs)))
523 (link (cdr (assoc "link" attrs)))
524 (plan (cdr (assoc "plan" attrs)))
525 (date (cdr (assoc "date" attrs))))
526 (goto-char beg)
527 (planner-insert-markup
528 (muse-markup-text 'planner-begin-task
529 status
530 priority
531 (concat priority number " "
532 (planner-publish-task-status-collapse status)
533 " ")))
534 (goto-char end)
535 (when link
536 (insert " (" (planner-make-link link) ")"))
537 (planner-insert-markup (muse-markup-text 'planner-end-task)))))
539 (defun planner-publish-notes-section-tag (beg end)
540 "Replace the region BEG to END with the notes for this page."
541 (save-excursion
542 (planner-insert-markup (muse-markup-text 'planner-begin-note-section))
543 (forward-line 1)
544 (planner-insert-markup (muse-markup-text 'planner-begin-body))
545 (insert ?\n)
546 (goto-char end)
547 (planner-insert-markup (muse-markup-text 'planner-end-body))
548 (planner-insert-markup (muse-markup-text 'planner-end-note-section))))
550 (defun planner-publish-notes-tag (beg end)
551 "Replace the region BEG to END with an index of the notes for this page."
552 (delete-region beg end)
553 (insert "\n")
554 (mapcar
555 (lambda (item)
556 (insert (format " - [[%s%s][%s]]\n"
557 (planner-page-name)
558 (car item)
559 (planner-remove-links (cdr item)))))
560 (save-excursion
561 (find-file muse-publishing-current-file)
562 (planner-notes-get-headlines)))
563 (insert "\n"))
565 (defun planner-publish-past-notes-tag (beg end attrs)
566 "Replace the region BEG to END with an index of past notes.
567 If ATTRS is non-nil, it is an alist containing values for
568 DIRECTORY and START."
569 (let ((files (save-excursion
570 (find-file muse-publishing-current-file)
571 (planner-get-day-pages nil nil t)))
572 (earliest (cdr (assoc "start" attrs))))
573 (while files
574 (when (or (null earliest)
575 (not (string-lessp (caar files) earliest)))
576 (let ((title-lines (list t)))
577 (with-temp-buffer
578 (insert-file-contents (cdar files))
579 (while (re-search-forward "^\\.#\\([0-9]+\\)\\s-+\\(.+\\)" nil t)
580 (nconc title-lines (list (cons (match-string 1)
581 (match-string 2))))))
582 (setq title-lines (cdr title-lines))
583 (when title-lines
584 (insert (planner-make-link (planner-page-name (caar files)))
585 " ::\n")
586 (planner-insert-markup " <dl class=\"contents\">\n")
587 (while title-lines
588 (planner-insert-markup " <dt class=\"contents\">")
589 (insert (format "[[%s#%s][%s]]"
590 (planner-page-name (caar files))
591 (caar title-lines) (cdar title-lines)))
592 (planner-insert-markup "</dt>\n")
593 (setq title-lines (cdr title-lines)))
594 (planner-insert-markup " </dl>\n\n"))))
595 (setq files (cdr files)))))
597 (defun planner-publish-note-tag (beg end attrs)
598 (save-excursion
599 (let ((anchor (or (cdr (assoc "anchor" attrs)) ""))
600 (timestamp (or (cdr (assoc "timestamp" attrs)) ""))
601 (link (or (cdr (assoc "link" attrs)) ""))
602 (categories (or (cdr (assoc "categories" attrs)) "")))
604 (goto-char beg)
605 (planner-insert-markup (muse-markup-text 'planner-begin-note
606 anchor
607 (concat "#" anchor)))
608 (goto-char end)
609 (planner-insert-markup (muse-markup-text 'planner-begin-note-details
610 timestamp)
611 (muse-markup-text 'planner-begin-note-link))
612 (insert link)
613 (planner-insert-markup (muse-markup-text 'planner-end-note-link)
614 (muse-markup-text 'planner-begin-note-categories))
615 (insert categories)
616 (planner-insert-markup (muse-markup-text 'planner-end-note-categories))
617 (insert ?\n)
618 (planner-insert-markup (muse-markup-text 'planner-end-note-details))
619 (planner-insert-markup (muse-markup-text 'planner-end-note)))))
621 ;;;_ + helper routine
623 (defun planner-publish-task-status-expand (status)
624 (cond
625 ((string= status "_") "open")
626 ((string= status "o") "in-progress")
627 ((string= status "D") "delegated")
628 ((string= status "P") "pending")
629 ((string= status "X") "done")
630 ((string= status "C") "cancelled")
631 (t "unknown")))
633 (defun planner-publish-task-status-collapse (status)
634 (cond
635 ((string= status "open") "_")
636 ((string= status "in-progress") "o")
637 ((string= status "delegated") "D")
638 ((string= status "pending") "P")
639 ((string= status "done") "X")
640 ((string= status "cancelled") "C")
641 (t "?")))
643 (defun planner-publish-section-close (depth text)
644 "Find where the closing tag of DEPTH should go, and insert TEXT."
645 (let (not-end)
646 (save-excursion
647 (while (and (setq not-end (re-search-forward
648 (concat "^\\*\\{1," (number-to-string depth)
649 "\\}\\s-+")
650 nil t))
651 (get-text-property (match-beginning 0) 'read-only)))
652 (if not-end
653 (forward-line 0)
654 (goto-char (point-max)))
655 (cond ((not (eq (char-before) ?\n))
656 (insert "\n\n"))
657 ((not (eq (char-before (1- (point))) ?\n))
658 (insert "\n")))
659 (insert text)
660 (insert "\n"))))
662 (defvar planner-section-tagnames
663 '(("Tasks" . "tasks-section")
664 ("Notes" . "notes-section"))
665 "Alist of sections and their tag name.")
667 (defun planner-publish-section-tagname (text)
668 "A routine that checks `planner-section-tagnames' for tagname."
669 (let ((tagname (cdr (assoc text planner-section-tagnames))))
670 (if tagname
671 tagname
672 "nested-section")))
674 (defun planner-publish-section ()
675 "Publish the current heading as a section."
676 (let* ((depth (length (match-string 1)))
677 (title (buffer-substring (match-end 0) (planner-line-end-position)))
678 (tagname (planner-publish-section-tagname title)))
679 (delete-region (match-beginning 0) (match-end 0))
680 (insert (format "<%s level=\"%s\"><title level=\"%s\">"
681 tagname depth (1+ depth)))
682 (end-of-line)
683 (insert "</title>")
684 (planner-publish-section-close depth (format "</%s>" tagname))))
686 ;;;_ + Planner Style Definitions
688 (unless (assoc "planner-xml" muse-publishing-styles)
689 (muse-derive-style "planner-xml" "xml"
690 :regexps 'planner-publish-markup-regexps
691 :functions 'planner-publish-markup-functions
692 :tags 'planner-publish-markup-tags
693 :strings 'planner-xml-markup-strings
694 :before 'planner-publish-prepare-buffer
695 :after 'planner-publish-finalize-buffer
696 :header 'planner-xml-header
697 :footer 'planner-xml-footer)
698 (muse-derive-style "planner-html" "html"
699 :regexps 'planner-publish-markup-regexps
700 :functions 'planner-publish-markup-functions
701 :tags 'planner-publish-markup-tags
702 :strings 'planner-html-markup-strings
703 :before 'planner-publish-prepare-buffer
704 :after 'planner-publish-finalize-buffer
705 :header 'planner-html-header
706 :footer 'planner-html-footer)
707 (muse-derive-style "planner-xhtml" "xhtml"
708 :regexps 'planner-publish-markup-regexps
709 :functions 'planner-publish-markup-functions
710 :tags 'planner-publish-markup-tags
711 :strings 'planner-html-markup-strings
712 :before 'planner-publish-prepare-buffer
713 :after 'planner-publish-finalize-buffer
714 :header 'planner-xhtml-header
715 :footer 'planner-xhtml-footer))
717 (provide 'planner-publish)
719 ;;; planner-publish.el ends here