Fix problem introduced by recent commit that broke using SPC as separator.
[planner-el.git] / planner-accomplishments.el
blobe0b883fb446ac097c815bed28a7a507394c25f2f
1 ;;; planner-accomplishments.el --- Accomplishment reports for planner.el
3 ;; Copyright (C) 2004, 2005, 2006, 2008 Free Software Foundation, Inc.
5 ;; Emacs Lisp Archive Entry
6 ;; Filename: planner-accomplishments.el
7 ;; Keywords: hypermedia
8 ;; Author: Sandra Jean Chua (Sacha) <sacha@free.net.ph>
9 ;; Description: Produce accomplishment reports for planner.el
10 ;; URL: http://www.wjsullivan.net/PlannerMode.html
11 ;; Compatibility: Emacs20, Emacs21, Emacs22, XEmacs21
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 ;; planner-accomplishments.el produces accomplishment reports for
33 ;; planner files. On date pages, it summarizes tasks by associated PlanPage.
35 ;; DISPLAYING A TEMPORARY BUFFER
37 ;; You can call `planner-accomplishments-show' to display a buffer
38 ;; containing the current page's accomplishment report.
40 ;; REWRITING SECTIONS OF YOUR PLANNER
42 ;; Choose this approach if you want accomplishment reports to be in
43 ;; their own section and you would like them to be readable in your
44 ;; plain text files even outside Emacs. Caveat: The accomplishment
45 ;; section should already exist in your template and will be rewritten
46 ;; when updated.
48 ;; To use, set `planner-accomplishments-section' to the name of the
49 ;; section to rewrite (default: "Accomplishments"). If you want
50 ;; rewriting to be automatically performed, call
51 ;; `planner-accomplishments-insinuate'. The accomplishments will be
52 ;; rewritten whenever you save a planner page. If you want rewriting
53 ;; to be manual, call `planner-accomplishments-update'.
55 ;; TODO
57 ;; - On plan pages, it summarizes tasks by associated date page
58 ;; (controlled by `planner-accomplishments-plan-page-days'). Tasks
59 ;; are broken down by status.
61 (require 'planner)
63 ;;; Code:
65 ;;; USER VARIABLES -----------------------------------------------------------
67 (defgroup planner-accomplishments nil
68 "Accomplishment reports for planner.el."
69 :prefix "planner-accomplishments"
70 :group 'planner)
72 (defcustom planner-accomplishments-section "Accomplishments"
73 "Header for the accomplishments section in a plan page."
74 :type 'string
75 :group 'planner-accomplishments)
77 (defcustom planner-accomplishments-status-display
78 '(("_" . "Unfinished")
79 ("o" . "In progress")
80 ("D" . "Delegated")
81 ("P" . "Postponed")
82 ("X" . "Completed")
83 ("C" . "Cancelled"))
84 "Alist of status-label maps also defining the order of display."
85 :type '(alist :key-type string :value-type string)
86 :group 'planner-accomplishments)
88 (defvar planner-accomplishments-buffer "*Planner Accomplishments*"
89 "Buffer name for accomplishment reports from `planner-accomplishments-show'.")
91 ;;;###autoload
92 (defun planner-accomplishments-insinuate ()
93 "Automatically call `planner-accomplishments-update'."
94 (add-hook 'planner-mode-hook
95 (lambda ()
96 (add-hook
97 (if (and (boundp 'write-file-functions)
98 (not (featurep 'xemacs)))
99 'write-file-functions
100 'write-file-hooks)
101 'planner-accomplishments-update nil t))))
103 ;;;###autoload
104 (defun planner-accomplishments-update ()
105 "Update `planner-accomplishments-section'."
106 (interactive)
107 (save-excursion
108 (save-restriction
109 (when (planner-narrow-to-section planner-accomplishments-section)
110 (delete-region (point-min) (point-max))
111 (insert "* " planner-accomplishments-section "\n\n"
112 (planner-accomplishments-format-table
113 (planner-accomplishments-extract-data))
114 "\n")
115 nil)))) ; Return nil for write-file-functions
117 ;;;###autoload
118 (defun planner-accomplishments-show ()
119 "Display a buffer with the current page's accomplishment report."
120 (interactive)
121 (let ((page (and (planner-derived-mode-p 'planner-mode)
122 (planner-page-name)))
123 (data (planner-accomplishments-extract-data)))
124 (when page
125 (set-buffer (get-buffer-create planner-accomplishments-buffer))
126 (cd (planner-directory))
127 (setq muse-current-project (muse-project planner-project))
128 (planner-mode)
129 (erase-buffer)
130 (insert "Accomplishment report for "
131 (planner-make-link page) "\n\n"
132 (planner-accomplishments-format-table data)
133 "\n")
134 (goto-char (point-min))
135 (display-buffer (get-buffer-create planner-accomplishments-buffer) t))))
137 (defun planner-accomplishments-extract-data ()
138 "Return a list of ((link . status) . count) for tasks on the current page."
139 (save-excursion
140 (save-restriction
141 (widen)
142 (goto-char (point-min))
143 (let (results)
144 (while (re-search-forward planner-task-regexp nil t)
145 (let* ((info (planner-current-task-info))
146 (key (cons (planner-task-link info)
147 (planner-task-status info)))
148 (entry (assoc key results)))
149 (if entry
150 (setcdr entry (1+ (cdr entry)))
151 (setq results (cons (cons key 1) results)))))
152 results))))
154 (defun planner-accomplishments-total-by-link (data)
155 "Return a list of (link . total)."
156 (let (results)
157 (mapcar
158 (lambda (item)
159 (let ((entry (assoc (car (car item)) results)))
160 (if entry
161 (setcdr entry (+ (cdr entry) (cdr item)))
162 (setq results (cons (cons (car (car item)) (cdr item)) results)))))
163 data)
164 results))
166 (defun planner-accomplishments-total-by-status (data)
167 "Return a list of (status . total)."
168 (let (results)
169 (mapcar
170 (lambda (item)
171 (let ((entry (assoc (cdr (car item)) results)))
172 (if entry
173 (setcdr entry (+ (cdr entry) (cdr item)))
174 (setq results (cons (cons (cdr (car item)) (cdr item)) results)))))
175 data)
176 results))
178 (defun planner-accomplishments-format-table (data)
179 "Format DATA from `planner-accomplishments-extract-data' into a table."
180 (let ((links (planner-accomplishments-total-by-link data))
181 (status (planner-accomplishments-total-by-status data))
182 (page-format "%-30.30s")
183 displayed-status)
184 (setq links (sort links (lambda (a b) (> (cdr a) (cdr b)))))
185 ;; Determine the status to be displayed
186 (with-temp-buffer
187 (insert (format page-format "Link"))
188 (mapcar
189 (lambda (s)
190 (when (assoc (car s) status)
191 (insert " | " (cdr s))
192 (setq displayed-status
193 (cons (cons (car s)
194 (format "%%%dd" (length (cdr s))))
195 displayed-status))))
196 planner-accomplishments-status-display)
197 (insert " | Total\n")
198 (setq displayed-status (nreverse displayed-status))
199 (mapcar
200 (lambda (page)
201 (insert (if (car page)
202 (let ((len (length (car page)))
203 (link (planner-make-link (car page))))
204 (if (< len 30)
205 (concat link (make-string (- 30 len) ?\ ))
206 link))
207 "nil"))
208 (mapcar
209 (lambda (s)
210 (insert
211 (format (concat " | " (cdr s))
212 (or (cdr (assoc (cons (car page) (car s)) data)) 0))))
213 displayed-status)
214 (insert (format " | %5d\n" (cdr page))))
215 links)
216 (insert (format page-format "Total"))
217 (let ((count 0))
218 (mapcar
219 (lambda (s)
220 (setq count (+ count (cdr (assoc (car s) status))))
221 (insert
222 (format (concat " | " (cdr s))
223 (cdr (assoc (car s) status)))))
224 displayed-status)
225 (insert (format " | %5d\n" count)))
226 (buffer-string))))
228 (provide 'planner-accomplishments)
230 ;;; planner-accomplishments.el ends here