Fix issue with planner-multi breaking completion for other Emacs functions. Closes...
[planner-el.git] / planner-publish.el
blobdb990197086c89b7fcefcb587b77740605a850d0
1 ;;; planner-publish.el --- planner-specific publishing
3 ;; Copyright (C) 2005, 2006, 2008 Peter K. Lee
4 ;; Parts copyright (C) 2005, 2008 Chris McMahan
5 ;; Parts copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
6 ;; Parts copyright (C) 2005, 2008 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 3, 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 (unless (featurep 'muse-nested-tags)
75 (error (concat "Your version of Muse is too old. Please upgrade to"
76 " at least Muse 3.03.")))
78 (defgroup planner-publish nil
79 "Options controlling the behavior of PLANNER publishing.
80 See `planner-publish' for more information."
81 :group 'planner)
83 (defcustom planner-publish-markup-regexps
84 '((1275 "^#\\([A-C]\\)\\([0-9]*\\)\\s-*\\([_oXDCP]\\)\\s-*\\(.+\\)" 0 task)
85 (1280 "^\\.#[0-9]+\\s-*" 0 note)
86 (3200 planner-date-regexp 0 link))
87 "List of markup rules for publishing PLANNER.
88 For more on the structure of this list, see `muse-publish-markup-regexps'."
89 :type '(repeat (choice
90 (list :tag "Markup rule"
91 integer
92 (choice regexp symbol)
93 integer
94 (choice string function symbol))
95 function))
96 :group 'planner-publish)
98 (defcustom planner-publish-markup-functions
99 '((task . planner-publish-markup-task)
100 (note . planner-publish-markup-note))
101 "An alist of style types to custom functions for that kind of text.
102 For more on the structure of this list, see
103 `muse-publish-markup-functions'."
104 :type '(alist :key-type symbol :value-type function)
105 :group 'planner-publish)
107 (defcustom planner-publish-markup-tags
108 '(("nested-section" t nil t planner-publish-nested-section-tag)
109 ("title" t t nil planner-publish-title-tag)
110 ("content" t nil nil planner-publish-content-tag)
111 ("diary-section" t nil nil planner-publish-diary-section-tag)
112 ("tasks-section" t nil nil planner-publish-tasks-section-tag)
113 ("notes-section" t nil nil planner-publish-notes-section-tag)
114 ("notes" nil nil nil planner-publish-notes-tag)
115 ("past-notes" nil t nil planner-publish-past-notes-tag)
116 ("task" t t nil planner-publish-task-tag)
117 ("note" t t nil planner-publish-note-tag))
118 "A list of tag specifications, for specially marking up PLANNER.
119 See `muse-publish-markup-tags' for more information."
120 :type '(repeat (list (string :tag "Markup tag")
121 (boolean :tag "Expect closing tag" :value t)
122 (boolean :tag "Parse attributes" :value nil)
123 (boolean :tag "Nestable" :value nil)
124 function))
125 :group 'planner-publish)
127 ;;;_ + XML specific customizations
129 (defcustom planner-xml-markup-strings
130 '((planner-begin-nested-section . "<section>")
131 (planner-end-nested-section . "</section>")
132 (planner-begin-title . "<title>")
133 (planner-end-title . "</title>")
134 (planner-begin-content . "")
135 (planner-end-content . "")
136 (planner-begin-body . "")
137 (planner-end-body . "")
138 (planner-begin-diary-section . "<diary>")
139 (planner-end-diary-section . "</diary>")
140 (planner-begin-task-section . "<tasks>")
141 (planner-end-task-section . "</tasks>")
142 (planner-begin-task-body . "")
143 (planner-end-task-body . "")
144 (planner-begin-note-section . "<notes>")
145 (planner-end-note-section . "</notes>")
146 (planner-begin-task . "<task status=\"%s\" priority=\"%s\">")
147 (planner-end-task . "</task>")
148 (planner-begin-note . "<note number=\"%s\">")
149 (planner-end-note . "</note>")
150 (planner-begin-note-details . "<details><timestamp>%s</timestamp>")
151 (planner-end-note-details . "</details>")
152 (planner-begin-note-link . "<references>")
153 (planner-end-note-link . "</references>")
154 (planner-begin-note-categories . "<categories>")
155 (planner-end-note-categories . "</categories>"))
156 "Strings used for marking up text as XML.
157 These cover the most basic kinds of markup, the handling of which
158 differs little between the various styles.
160 If a markup rule is not found here, `muse-xml-markup-strings' is
161 searched."
162 :type '(alist :key-type symbol :value-type string)
163 :group 'planner-publish)
165 (defcustom planner-xml-header
166 "<?xml version=\"1.0\" encoding=\"<lisp>(muse-xml-encoding)</lisp>\"?>
167 <PLANNER>
168 <pageinfo>
169 <title><lisp>(muse-publishing-directive \"title\")</lisp></title>
170 <author><lisp>(muse-publishing-directive \"author\")</lisp></author>
171 <maintainer><lisp>(muse-style-element :maintainer)</lisp></maintainer>
172 <pubdate><lisp>(muse-publishing-directive \"date\")</lisp></pubdate>
173 </pageinfo>
174 <!-- Page published by Emacs Muse begins here -->\n"
175 "Header used for publishing PLANNER XML files.
176 This may be text or a filename."
177 :type 'string
178 :group 'planner-publish)
180 (defcustom planner-xml-footer "
181 <!-- Page published by Emacs Muse ends here -->
182 </PLANNER>\n"
183 "Footer used for publishing PLANNER XML files.
184 This may be text or a filename."
185 :type 'string
186 :group 'planner-publish)
188 ;;;_ + HTML specific customizations
190 (defcustom planner-html-markup-strings
191 '((planner-begin-nested-section . "<div class=\"section\">")
192 (planner-end-nested-section . "</div>")
193 (planner-begin-title . "<h%s>")
194 (planner-end-title . "</h%s>")
195 (planner-begin-content . "<div class=\"content\">")
196 (planner-end-content . "</div>")
197 (planner-begin-body . "<div class=\"body\">")
198 (planner-end-body . "</div>")
199 (planner-begin-diary-section . "<div id=\"diary\" class=\"section\">")
200 (planner-end-diary-section . "</div>")
201 (planner-begin-task-section . "<div id=\"tasks\" class=\"section\">")
202 (planner-end-task-section . "</div>")
203 (planner-begin-task-body . "<ul class=\"body\">")
204 (planner-end-task-body . "</ul>")
205 (planner-begin-note-section . "<div id=\"notes\" class=\"section\">")
206 (planner-end-note-section . "</div>")
207 (planner-begin-task . "<li class=\"task\"><span class=\"%s\"><span class=\"%s\" id=\"%s\">%s</span>")
208 (planner-end-task . "</span></li>")
209 (planner-begin-note . "<div class=\"note\"><a name=\"%s\"></a><span class=\"anchor\">%s</span>")
210 (planner-end-note . "</div>")
211 (planner-begin-note-details . "<div class=\"details\"><span class=\"timestamp\">%s</span>")
212 (planner-end-note-details . "</div>")
213 (planner-begin-note-link . " <span class=\"link\">")
214 (planner-end-note-link . "</span>")
215 (planner-begin-note-categories . " <span class=\"categories\">")
216 (planner-end-note-categories . "</span>"))
217 "Strings used for marking up text as HTML.
218 These cover the most basic kinds of markup, the handling of which
219 differs little between the various styles.
221 If a markup rule is not found here, `muse-html-markup-strings' is
222 searched."
223 :type '(alist :key-type symbol :value-type string)
224 :group 'planner-publish)
226 (defcustom planner-html-style-sheet
227 "<style type=\"text/css\">
228 body {
229 background: white; color: black;
230 margin-left: 3%; margin-right: 3%;
233 p { margin-top: 3px; margin-bottom: 3px; }
234 p.verse { margin-left: 3% }
236 h1,h2,h3,h4,h5 { margin:0; padding:0; }
238 h1 { padding: 10px; margin-bottom: 10px; }
240 table.muse-table { margin: 0; font-size: 11px;
241 border-collapse: collapse;
242 background: #e2effa;
243 border: 1px solid #aadeed; }
245 table.muse-table tbody td { border: 1px solid #ccdeed; }
247 .example { margin-left: 5px; padding: 3px;
248 background: #fffffc;
249 border: 1px solid #ccdeed; }
251 /* nested sections */
252 .section { margin: 0; padding: 10px;
253 margin-bottom: 15px;
254 font-size: 12px; }
256 .section .section { margin: 0; margin-left: 5px;
257 font-size: 11px; }
259 .title { margin: 0; padding; 0 }
261 /* optional calendar section */
262 .calendar { float: right; }
263 table.month-calendar { font-size: 9px; }
265 /* Diary section */
266 #diary p { margin-top: 1em; }
268 /* Tasks section */
269 .task .A { color: red }
270 .task .B { color: green }
271 .task .C { color: navy }
272 .task .done { color: gray; text-decoration: line-through; }
273 .task .cancelled { color: gray; text-decoration: italic; }
275 /* Notes section */
276 .note { margin-top: 1.5em; }
277 .note .anchor { float: left; margin-right: 5px; }
278 .note .details { margin-top: .5em; }
280 </style>"
281 "Store your stylesheet definitions here. The provided default
282 is for reference only. You definitely want to customize this for
283 your particular needs & wants. This is used in
284 `planner-html-header' and `planner-xhtml-header'. Refer to
285 `muse-html-style-sheet' for details on usage. You may simply
286 override the above by specifying an explicit link to a CSS file."
287 :type 'string
288 :group 'planner-publish)
290 (defcustom planner-html-header
291 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">
292 <html>
293 <head>
294 <title><lisp>
295 (concat (muse-publishing-directive \"title\")
296 (let ((author (muse-publishing-directive \"author\")))
297 (if (not (string= author (user-full-name)))
298 (concat \" (by \" author \")\"))))</lisp></title>
299 <meta name=\"generator\" content=\"muse.el\">
300 <meta http-equiv=\"<lisp>muse-html-meta-http-equiv</lisp>\"
301 content=\"<lisp>muse-html-meta-content-type</lisp>\">
302 <lisp>
303 (let ((maintainer (muse-style-element :maintainer)))
304 (when maintainer
305 (concat \"<link rev=\\\"made\\\" href=\\\"\" maintainer \"\\\">\")))
306 </lisp>
307 <lisp>planner-html-style-sheet</lisp>
308 </head>
309 <body>
310 <div id=\"content\">
311 <h1><span><lisp>
312 (concat (muse-publishing-directive \"title\")
313 (let ((author (muse-publishing-directive \"author\")))
314 (if (not (string= author (user-full-name)))
315 (concat \" (by \" author \")\"))))</lisp></span></h1>
316 <div id=\"inner-header\">
317 <lisp>planner-html-inner-header</lisp>
318 </div>
319 <div id=\"muse-sections\">
320 <!-- Page published by Emacs Muse begins here -->\n"
321 "Header used for publishing PLANNER HTML files.
322 This may be text or a filename."
323 :type 'string
324 :group 'planner-publish)
326 (defcustom planner-html-footer "
327 <!-- Page published by Emacs Muse ends here -->
328 </div>
329 <div id=\"inner-footer\">
330 <lisp>planner-html-inner-footer</lisp>
331 </div>
332 </div>
333 </body>
334 </html>\n"
335 "Footer used for publishing PLANNER HTML files.
336 This may be text or a filename."
337 :type 'string
338 :group 'planner-publish)
340 (defcustom planner-xhtml-header
341 "<?xml version=\"1.0\" encoding=\"<lisp>
342 (muse-html-encoding)</lisp>\"?>
343 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
344 \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
345 <html xmlns=\"http://www.w3.org/1999/xhtml\">
346 <head>
347 <title><lisp>
348 (concat (muse-publishing-directive \"title\")
349 (let ((author (muse-publishing-directive \"author\")))
350 (if (not (string= author (user-full-name)))
351 (concat \" (by \" author \")\"))))</lisp></title>
352 <meta name=\"generator\" content=\"muse.el\" />
353 <meta http-equiv=\"<lisp>muse-html-meta-http-equiv</lisp>\"
354 content=\"<lisp>muse-html-meta-content-type</lisp>\" />
355 <lisp>
356 (let ((maintainer (muse-style-element :maintainer)))
357 (when maintainer
358 (concat \"<link rev=\\\"made\\\" href=\\\"\" maintainer \"\\\" />\")))
359 </lisp>
360 <lisp>planner-html-style-sheet</lisp>
361 </head>
362 <body>
363 <div id=\"content\">
364 <h1><span><lisp>
365 (concat (muse-publishing-directive \"title\")
366 (let ((author (muse-publishing-directive \"author\")))
367 (if (not (string= author (user-full-name)))
368 (concat \" (by \" author \")\"))))</lisp></span></h1>
369 <div id=\"inner-header\">
370 <lisp>planner-html-inner-header</lisp>
371 </div>
372 <div id=\"muse-sections\">
373 <!-- Page published by Emacs Muse begins here -->\n"
374 "Header used for publishing PLANNER XHTML files.
375 This may be text or a filename."
376 :type 'string
377 :group 'planner-publish)
379 (defcustom planner-xhtml-footer "
380 <!-- Page published by Emacs Muse ends here -->
381 </div>
382 <div id=\"inner-footer\">
383 <lisp>planner-html-inner-footer</lisp>
384 </div>
385 </div>
386 </body>
387 </html>\n"
388 "Footer used for publishing PLANNER XHTML files.
389 This may be text or a filename."
390 :type 'string
391 :group 'planner-publish)
393 (defcustom planner-html-inner-header ""
394 "Extra header section that can be embedded within
395 `planner-html-header' and `planner-xhtml-header'."
396 :type 'string
397 :group 'planner-publish)
399 (defcustom planner-html-inner-footer ""
400 "Extra footer section that can be embedded within
401 `planner-html-footer' and `planner-xhtml-footer'."
402 :type 'string
403 :group 'planner-publish)
405 ;;;_ + Publishing hooks
407 (defcustom planner-publish-prepare-regexps
408 '((100 "^\\(\\*+\\)\\s-+" 0 planner-publish-section))
409 "List of markup rules to apply before publishing a page with Planner.
410 See `muse-publish-markup-regexps' for details on the syntax used."
411 :type '(repeat (choice
412 (list :tag "Markup rule"
413 integer
414 (choice regexp symbol)
415 integer
416 (choice string function symbol))
417 function))
418 :group 'planner-publish)
420 (defcustom planner-publish-finalize-regexps
422 "List of markup rules to apply after publishing a page with Planner.
423 See `muse-publish-markup-regexps' for details on the syntax used."
424 :type '(repeat (choice
425 (list :tag "Markup rule"
426 integer
427 (choice regexp symbol)
428 integer
429 (choice string function symbol))
430 function))
431 :group 'planner-publish)
433 (defun planner-publish-prepare-buffer ()
434 (goto-char (point-min))
435 (muse-publish-markup "preparing Planner page"
436 planner-publish-prepare-regexps)
437 ;; indicate that we are to continue preparing the buffer
438 nil)
440 (defun planner-publish-finalize-buffer ()
441 (goto-char (point-min))
442 (muse-publish-markup "finalizing Planner page"
443 planner-publish-finalize-regexps)
444 ;; indicate that we are to continue finalizing the buffer
445 nil)
447 ;;;_ + Markup
449 (defvar planner-publish-ignore-url-desc-specials nil
450 "If non-nil, do not escape specials in URL descriptions.")
452 (defun planner-publish-decide-specials (context)
453 "Determine the specials to escape for Planner, depending on CONTEXT."
454 (if (and (eq context 'url-desc)
455 planner-publish-ignore-url-desc-specials)
457 (muse-xml-decide-specials context)))
459 (defun planner-publish-markup-task ()
460 "Replace tasks with XML representation of task data."
461 (save-restriction
462 (narrow-to-region
463 (planner-line-beginning-position)
464 (planner-line-end-position))
465 (let ((info (planner-current-task-info)))
466 (delete-region (point-min) (point-max))
467 (forward-line 1)
468 (insert
469 (format (concat "<task id=\"%s\" priority=\"%s\" status=\"%s\""
470 " link=\"%s\" plan=\"%s\" date=\"%s\">")
471 (or (planner-task-number info) "")
472 (or (planner-task-priority info) "")
473 (or (planner-publish-task-status-expand
474 (planner-task-status info)) "")
475 (or (planner-task-link-text info) "")
476 (or (planner-task-plan info) "")
477 (or (planner-task-date info) "")))
478 ;; mark this area read only for safety's sake
479 (planner-insert-markup (planner-task-description info))
480 (insert "</task>"))))
482 (defun planner-publish-markup-note ()
483 "Replace note with XML representation of note data. Borrowed
484 heavily from Sacha's personal configs."
485 (save-restriction
486 (narrow-to-region
487 (save-excursion (beginning-of-line) (point))
488 (or (save-excursion
489 (and (re-search-forward "^\\(\\.#\\|* \\|</notes-section>\\)" nil t)
490 (match-beginning 0)))
491 (point-max)))
492 (let ((info (planner-current-note-info t)))
493 (delete-region (point-min) (point-max))
494 (insert (format (concat "<note anchor=\"%s\" timestamp=\"%s\""
495 " link=\"%s\" categories=\"%s\">")
496 (planner-note-anchor info)
497 (or (planner-note-timestamp info) "")
498 (or (planner-note-link info) "")
499 (or (planner-note-link-text info) ""))
500 "<title level=\"3\">" (planner-note-title info) "</title>\n"
501 "<content>\n")
502 (planner-insert-markup (planner-note-body info))
503 (insert "\n\n</content>\n</note>\n"))))
506 ;;;_ + Tags
508 (defun planner-insert-markup (&rest args)
509 (if (fboundp 'muse-insert-markup)
510 (apply 'muse-insert-markup args)
511 (let ((beg (point)))
512 (apply 'insert args)
513 (muse-publish-mark-read-only beg (point)))))
515 (defun planner-publish-nested-section-tag (beg end)
516 "Generated by `planner-publish-section', the nested section tag
517 now takes in TITLE and LEVEL attributes.
519 This is related to the Muse concept of sections, but done before
520 marking up the buffer, and with special actions done on the title
521 of each section."
522 (save-excursion
523 (goto-char beg)
524 (planner-insert-markup (muse-markup-text 'planner-begin-nested-section))
525 (goto-char end)
526 (planner-insert-markup (muse-markup-text 'planner-end-nested-section))))
528 (defun planner-publish-title-tag (beg end attrs)
529 (let ((level (cdr (assoc "level" attrs))))
530 (save-excursion
531 (goto-char beg)
532 (planner-insert-markup (muse-markup-text 'planner-begin-title level))
533 (goto-char end)
534 (planner-insert-markup (muse-markup-text 'planner-end-title level)))))
536 (defun planner-publish-content-tag (beg end)
537 (save-excursion
538 (goto-char end)
539 (planner-insert-markup (muse-markup-text 'planner-end-content))
540 (goto-char beg)
541 (planner-insert-markup (muse-markup-text 'planner-begin-content))))
543 (defun planner-publish-diary-section-tag (beg end)
544 (save-excursion
545 (goto-char beg)
546 (planner-insert-markup (muse-markup-text 'planner-begin-diary-section))
547 (forward-line 1)
548 (muse-publish-verse-tag (point) end)
549 (goto-char end)
550 (insert "\n")
551 (planner-insert-markup (muse-markup-text 'planner-end-diary-section))))
553 (defun planner-publish-tasks-section-tag (beg end)
554 (save-excursion
555 (goto-char beg)
556 (planner-insert-markup (muse-markup-text 'planner-begin-task-section))
557 (forward-line 1)
558 (planner-insert-markup (muse-markup-text 'planner-begin-task-body))
559 (goto-char end)
560 (planner-insert-markup (muse-markup-text 'planner-end-task-body))
561 (planner-insert-markup (muse-markup-text 'planner-end-task-section))))
563 (defun planner-publish-task-tag (beg end attrs)
564 (save-excursion
565 (let ((number (cdr (assoc "id" attrs)))
566 (status (cdr (assoc "status" attrs)))
567 (priority (cdr (assoc "priority" attrs)))
568 (link (cdr (assoc "link" attrs)))
569 (plan (cdr (assoc "plan" attrs)))
570 (date (cdr (assoc "date" attrs))))
571 (remove-text-properties beg end
572 '(read-only nil rear-nonsticky nil))
573 (goto-char end)
574 (when link
575 (insert " (" (planner-make-link link) ")"))
576 (planner-insert-markup (muse-markup-text 'planner-end-task))
577 (goto-char beg)
578 (planner-insert-markup
579 (muse-markup-text 'planner-begin-task
580 status
581 priority
582 (if planner-use-task-numbers
583 (concat priority number)
584 (concat priority (number-to-string (random 134217727))))
585 (concat priority number " "
586 (planner-publish-task-status-collapse status)
587 " "))))))
589 (defun planner-publish-notes-section-tag (beg end)
590 "Replace the region BEG to END with the notes for this page."
591 (save-excursion
592 (planner-insert-markup (muse-markup-text 'planner-begin-note-section))
593 (forward-line 1)
594 (planner-insert-markup (muse-markup-text 'planner-begin-body))
595 (insert ?\n)
596 (goto-char end)
597 (planner-insert-markup (muse-markup-text 'planner-end-body))
598 (planner-insert-markup (muse-markup-text 'planner-end-note-section))))
600 (defun planner-publish-notes-tag (beg end)
601 "Replace the region BEG to END with an index of the notes for this page."
602 (delete-region beg end)
603 (insert "\n")
604 (mapcar
605 (lambda (item)
606 (insert (format " - [[%s%s][%s]]\n"
607 (planner-page-name)
608 (car item)
609 (planner-remove-links (cdr item)))))
610 (save-excursion
611 (find-file muse-publishing-current-file)
612 (planner-notes-get-headlines)))
613 (insert "\n"))
615 (defun planner-publish-past-notes-tag (beg end attrs)
616 "Replace the region BEG to END with an index of past notes.
617 If ATTRS is non-nil, it is an alist containing values for
618 DIRECTORY and START."
619 (let ((files (save-excursion
620 (find-file muse-publishing-current-file)
621 (planner-get-day-pages nil nil t)))
622 (earliest (cdr (assoc "start" attrs))))
623 (while files
624 (when (or (null earliest)
625 (not (string-lessp (caar files) earliest)))
626 (let ((title-lines (list t)))
627 (with-temp-buffer
628 (insert-file-contents (cdar files))
629 (while (re-search-forward "^\\.#\\([0-9]+\\)\\s-+\\(.+\\)" nil t)
630 (nconc title-lines (list (cons (match-string 1)
631 (match-string 2))))))
632 (setq title-lines (cdr title-lines))
633 (when title-lines
634 (insert (planner-make-link (planner-page-name (caar files)))
635 " ::\n")
636 (planner-insert-markup " <dl class=\"contents\">\n")
637 (while title-lines
638 (planner-insert-markup " <dt class=\"contents\">")
639 (insert (format "[[%s#%s][%s]]"
640 (planner-page-name (caar files))
641 (caar title-lines) (cdar title-lines)))
642 (planner-insert-markup "</dt>\n")
643 (setq title-lines (cdr title-lines)))
644 (planner-insert-markup " </dl>\n\n"))))
645 (setq files (cdr files)))))
647 (defun planner-publish-note-tag (beg end attrs)
648 (save-excursion
649 (let ((anchor (or (cdr (assoc "anchor" attrs)) ""))
650 (timestamp (or (cdr (assoc "timestamp" attrs)) ""))
651 (link (or (cdr (assoc "link" attrs)) ""))
652 (categories (or (cdr (assoc "categories" attrs)) "")))
653 (remove-text-properties beg end
654 '(read-only nil rear-nonsticky nil))
655 (goto-char beg)
656 (planner-insert-markup (muse-markup-text 'planner-begin-note
657 anchor
658 (concat "#" anchor)))
659 (goto-char end)
660 (planner-insert-markup (muse-markup-text 'planner-begin-note-details
661 timestamp)
662 (muse-markup-text 'planner-begin-note-link))
663 (insert link)
664 (planner-insert-markup (muse-markup-text 'planner-end-note-link))
665 ;; remove link item from categories to avoid duplicates
666 (unless (or (string= link "") (string= categories ""))
667 (setq categories (planner-replace-regexp-in-string
668 (regexp-quote link) "" categories t t)))
669 (planner-insert-markup (muse-markup-text 'planner-begin-note-categories))
670 (insert categories)
671 (planner-insert-markup (muse-markup-text 'planner-end-note-categories))
672 (insert ?\n)
673 (planner-insert-markup (muse-markup-text 'planner-end-note-details))
674 (planner-insert-markup (muse-markup-text 'planner-end-note)))))
676 ;;;_ + helper routine
678 (defun planner-publish-task-status-expand (status)
679 (cond
680 ((string= status "_") "open")
681 ((string= status "o") "in-progress")
682 ((string= status "D") "delegated")
683 ((string= status "P") "pending")
684 ((string= status "X") "done")
685 ((string= status "C") "cancelled")
686 (t "unknown")))
688 (defun planner-publish-task-status-collapse (status)
689 (cond
690 ((string= status "open") "_")
691 ((string= status "in-progress") "o")
692 ((string= status "delegated") "D")
693 ((string= status "pending") "P")
694 ((string= status "done") "X")
695 ((string= status "cancelled") "C")
696 (t "?")))
698 (defun planner-publish-section-close (depth text)
699 "Find where the closing tag of DEPTH should go, and insert TEXT."
700 (let (not-end)
701 (save-excursion
702 (while (and (setq not-end (re-search-forward
703 (concat "^\\*\\{1," (number-to-string depth)
704 "\\}\\s-+")
705 nil t))
706 (get-text-property (match-beginning 0) 'read-only)))
707 (if not-end
708 (forward-line 0)
709 (goto-char (point-max)))
710 (cond ((not (eq (char-before) ?\n))
711 (insert "\n\n"))
712 ((not (eq (char-before (1- (point))) ?\n))
713 (insert "\n")))
714 (insert text)
715 (insert "\n"))))
717 (defvar planner-section-tagnames
718 '(("Diary" . "diary-section")
719 ("Tasks" . "tasks-section")
720 ("Notes" . "notes-section"))
721 "Alist of sections and their tag name.")
723 (defun planner-publish-section-tagname (text)
724 "A routine that checks `planner-section-tagnames' for tagname."
725 (let ((tagname (cdr (assoc text planner-section-tagnames))))
726 (if tagname
727 tagname
728 "nested-section")))
730 (defun planner-publish-section ()
731 "Publish the current heading as a section."
732 (let* ((depth (length (match-string 1)))
733 (title (buffer-substring (match-end 0) (planner-line-end-position)))
734 (tagname (planner-publish-section-tagname title)))
735 (delete-region (match-beginning 0) (match-end 0))
736 (insert (format "<%s level=\"%s\"><title level=\"%s\">"
737 tagname depth (1+ depth)))
738 (end-of-line)
739 (insert "</title>")
740 (planner-publish-section-close depth (format "</%s>" tagname))))
742 ;;;_ + Planner Style Definitions
744 (muse-derive-style "planner-xml" "xml"
745 :regexps 'planner-publish-markup-regexps
746 :functions 'planner-publish-markup-functions
747 :tags 'planner-publish-markup-tags
748 :specials 'planner-publish-decide-specials
749 :strings 'planner-xml-markup-strings
750 :before 'planner-publish-prepare-buffer
751 :after 'planner-publish-finalize-buffer
752 :header 'planner-xml-header
753 :footer 'planner-xml-footer)
755 (muse-derive-style "planner-html" "html"
756 :regexps 'planner-publish-markup-regexps
757 :functions 'planner-publish-markup-functions
758 :tags 'planner-publish-markup-tags
759 :specials 'planner-publish-decide-specials
760 :strings 'planner-html-markup-strings
761 :before 'planner-publish-prepare-buffer
762 :after 'planner-publish-finalize-buffer
763 :header 'planner-html-header
764 :footer 'planner-html-footer)
766 (muse-derive-style "planner-xhtml" "xhtml"
767 :regexps 'planner-publish-markup-regexps
768 :functions 'planner-publish-markup-functions
769 :tags 'planner-publish-markup-tags
770 :specials 'planner-publish-decide-specials
771 :strings 'planner-html-markup-strings
772 :before 'planner-publish-prepare-buffer
773 :after 'planner-publish-finalize-buffer
774 :header 'planner-xhtml-header
775 :footer 'planner-xhtml-footer)
777 (provide 'planner-publish)
779 ;;; planner-publish.el ends here