Commit | Line | Data |
---|---|---|
da2ee685 | 1 | ; todomode.el -- major mode for editing TODO list files |
3cb152f9 OS |
2 | |
3 | ;; --------------------------------------------------------------------------- | |
4 | ||
5 | ;; Note: You may copy this file freely for non-commercial use; otherwise, | |
6 | ;; please contact (address) O Seidel, Lessingstr 8, Eschborn, FRG | |
7 | ;; (e-mail ) Oliver.Seidel@cl.cam.ac.uk (2 Aug 1997) | |
8 | ||
a360be79 | 9 | ;; $Id: todomode.el,v 1.5 1997/08/05 14:43:39 os10000 Exp os10000 $ |
3cb152f9 | 10 | ;; |
384af0dd | 11 | ;; $Log: todomode.el,v $ |
a360be79 OS |
12 | ;; Revision 1.5 1997/08/05 14:43:39 os10000 |
13 | ;; Added improvements from Ron Gut <rgut@aware.com>. | |
14 | ;; Added category management. | |
15 | ;; | |
da2ee685 OS |
16 | ;; Revision 1.4 1997/08/04 16:18:45 os10000 |
17 | ;; Added Raise/Lower item. | |
18 | ;; | |
8cdc3b3d OS |
19 | ;; Revision 1.3 1997/08/03 12:47:26 os10000 |
20 | ;; Cleaned up variables, prefix and cursor position. | |
21 | ;; | |
7e6ed9b9 OS |
22 | ;; Revision 1.2 1997/08/03 12:15:28 os10000 |
23 | ;; It appears to work. | |
24 | ;; | |
384af0dd OS |
25 | ;; Revision 1.1 1997/08/03 12:15:13 os10000 |
26 | ;; Initial revision | |
3cb152f9 OS |
27 | ;; |
28 | ||
29 | ;; --------------------------------------------------------------------------- | |
30 | ||
7e6ed9b9 OS |
31 | ;; Description: |
32 | ;; | |
33 | ;; To get this to work, make emacs execute the line "(require 'todomode)" | |
34 | ;; and maybe initialise the variables below on startup. | |
35 | ;; | |
a360be79 OS |
36 | ;; Just for the case that you are wondering about the ugly name of this |
37 | ;; package: I am one of those unfortunate people who have DOS, LINUX and | |
38 | ;; OS/2 on one of their computers, so part of my home-filespace is shared | |
39 | ;; and stored on a DOS partition, which is accessible to all systems. If | |
40 | ;; you wish, you can of course rename the name of the file (and the last | |
41 | ;; command) to something more aisthetically (please don't argue about | |
42 | ;; this spelling ...) pleasing, like i.e. todo-mode. | |
43 | ;; | |
44 | ;; You will have the following facilities available: | |
7e6ed9b9 OS |
45 | ;; |
46 | ;; M-x todo-mode will enter the todo list screen, here type | |
da2ee685 OS |
47 | ;; + to go to next category |
48 | ;; - to go to previous category | |
7e6ed9b9 | 49 | ;; e to edit the current entry |
da2ee685 OS |
50 | ;; f to file the current entry, including a |
51 | ;; comment and timestamp | |
7e6ed9b9 OS |
52 | ;; i to insert a new entry |
53 | ;; k to kill the current entry | |
8cdc3b3d | 54 | ;; l lower the current entry's priority |
da2ee685 OS |
55 | ;; n for the next entry |
56 | ;; p for the previous entry | |
57 | ;; q to save the list and exit the buffer | |
58 | ;; r raise current entryk's priority | |
59 | ;; s to save the list | |
7e6ed9b9 | 60 | ;; |
a360be79 OS |
61 | ;; When you add a new entry, you are asked for the text and then for the |
62 | ;; category. I for example have categories for things that I want to do | |
63 | ;; in the office (like mail my mum), that I want to do in town (like buy | |
64 | ;; cornflakes) and things I want to do at home (move my suitcases). The | |
65 | ;; categories can be selected with the cursor keys and if you type in the | |
66 | ;; name of a category which didn't exist before, an empty category of the | |
67 | ;; desired name will be added. | |
68 | ;; | |
7e6ed9b9 OS |
69 | ;; I would recommend to add the following bindings to your global keymap: |
70 | ;; | |
da2ee685 | 71 | ;; (global-set-key "\C-ct" 'todo-show) |
7e6ed9b9 OS |
72 | ;; (global-set-key "\C-ci" 'todo-cmd-inst) |
73 | ;; | |
74 | ;; This will enable you to quickly find the todo-list, or to simply add an | |
75 | ;; entry, without changing to it and getting sidetracked from your current | |
76 | ;; project. | |
77 | ;; | |
da2ee685 OS |
78 | ;; I would also recommend that use the prefix "*/*" (by leaving the |
79 | ;; variable 'todo-prefix' untouched) so that the diary displays | |
80 | ;; each entry every day. | |
a360be79 OS |
81 | ;; |
82 | ;; For this, please read the documentation that goes with the calendar | |
83 | ;; since that will tell you how you can set up the fancy diary display | |
84 | ;; and use the #include command to include your todo list file as part | |
85 | ;; of your diary. | |
86 | ;; | |
87 | ;; Enjoy this package and express your gratitude by sending valuables | |
88 | ;; to my parents' address as listed above!!! | |
89 | ;; | |
90 | ;; Oliver Seidel | |
7e6ed9b9 OS |
91 | |
92 | ;; --------------------------------------------------------------------------- | |
93 | ||
3cb152f9 OS |
94 | ;; User-configurable variables: |
95 | ||
da2ee685 | 96 | (defvar todo-prefix "*/*" "TODO mode prefix when creating entries") |
7e6ed9b9 | 97 | (defvar todo-file-do "~/.todo-do" "TODO mode filename of list file") |
3cb152f9 OS |
98 | (defvar todo-file-done "~/.todo-done" "TODO mode filename of archive file") |
99 | (defvar todo-mode-hook nil "Hooks invoked when the *TODO* buffer is created.") | |
100 | ||
101 | ;; --------------------------------------------------------------------------- | |
102 | ||
103 | (require 'time-stamp) | |
104 | ||
da2ee685 OS |
105 | (defvar todo-mode-map (make-sparse-keymap) "TODO mode keymap. See `todo-mode'") |
106 | (define-key todo-mode-map "+" 'todo-cmd-forw) | |
107 | (define-key todo-mode-map "-" 'todo-cmd-back) | |
3cb152f9 | 108 | (define-key todo-mode-map "e" 'todo-cmd-edit) |
da2ee685 | 109 | (define-key todo-mode-map "f" 'todo-cmd-file) |
3cb152f9 OS |
110 | (define-key todo-mode-map "i" 'todo-cmd-inst) |
111 | (define-key todo-mode-map "k" 'todo-cmd-kill) | |
8cdc3b3d | 112 | (define-key todo-mode-map "l" 'todo-cmd-lowr) |
da2ee685 OS |
113 | (define-key todo-mode-map "n" 'todo-cmd-next) |
114 | (define-key todo-mode-map "p" 'todo-cmd-prev) | |
115 | (define-key todo-mode-map "q" 'todo-cmd-done) | |
116 | (define-key todo-mode-map "r" 'todo-cmd-rais) | |
117 | (define-key todo-mode-map "s" 'todo-cmd-save) | |
3cb152f9 | 118 | |
da2ee685 OS |
119 | (defun todo-cat-slct () |
120 | (let ((todo-category-name (nth todo-category-number todo-cats))) | |
121 | (setq mode-line-buffer-identification (concat "Category: " todo-category-name)) | |
122 | (widen) | |
123 | (goto-char (point-min)) | |
124 | (search-forward (concat "--- " todo-category-name)) | |
125 | (setq begin (+ (point-at-eol) 1)) | |
126 | (search-forward "--- End") | |
127 | (narrow-to-region begin (point-at-bol)) | |
128 | (goto-char (point-min)) | |
129 | ) | |
130 | ) | |
131 | ||
132 | (defun todo-cmd-forw () "Go forward to TODO list of next category." | |
133 | (interactive) | |
134 | (let ((todo-cat-cnt (- (length todo-cats) 1))) | |
135 | (setq todo-category-number (if (< todo-category-number todo-cat-cnt) | |
136 | (+ todo-category-number 1) 0)) | |
137 | (todo-cat-slct) | |
138 | ) | |
139 | ) | |
140 | ||
141 | (defun todo-cmd-back () "Go back to TODO list of previous category." | |
142 | (interactive) | |
143 | (let ((todo-cat-cnt (- (length todo-cats) 1))) | |
144 | (setq todo-category-number (if (> todo-category-number 0) | |
145 | (- todo-category-number 1) todo-cat-cnt)) | |
146 | (todo-cat-slct) | |
147 | ) | |
148 | ) | |
149 | ||
150 | (defun todo-cmd-prev () "Select previous entry of TODO list." | |
3cb152f9 OS |
151 | (interactive) |
152 | (forward-line -1) | |
153 | (beginning-of-line nil) | |
154 | (message "") | |
155 | ) | |
156 | ||
da2ee685 | 157 | (defun todo-cmd-next () "Select next entry of TODO list." |
3cb152f9 OS |
158 | (interactive) |
159 | (forward-line 1) | |
160 | (beginning-of-line nil) | |
161 | (message "") | |
162 | ) | |
163 | ||
da2ee685 OS |
164 | (defun todo-cmd-save () "Save the TODO list." |
165 | (interactive) | |
166 | (save-buffer) | |
167 | ) | |
168 | ||
169 | (defun todo-cmd-done () "Done with TODO list for now." | |
3cb152f9 | 170 | (interactive) |
da2ee685 OS |
171 | (widen) |
172 | (save-buffer) | |
7e6ed9b9 OS |
173 | (beginning-of-line nil) |
174 | (message "") | |
3cb152f9 OS |
175 | (bury-buffer) |
176 | ) | |
177 | ||
da2ee685 | 178 | (defun todo-line () "Find current line in buffer." (buffer-substring (point-at-bol) (point-at-eol))) |
3cb152f9 | 179 | |
da2ee685 | 180 | (defun todo-cmd-edit () "Edit current TODO list entry." |
3cb152f9 | 181 | (interactive) |
da2ee685 OS |
182 | (let ((todo-entry (todo-line))) |
183 | (delete-region (point-at-bol) (point-at-eol)) | |
184 | (insert (read-from-minibuffer "Edit: " todo-entry)) | |
185 | (beginning-of-line nil) | |
186 | (message "") | |
187 | ) | |
3cb152f9 OS |
188 | ) |
189 | ||
190 | (defvar todo-prv-lne 0 "previous line that I asked about.") | |
191 | (defvar todo-prv-ans 0 "previous answer that I got.") | |
192 | ||
193 | (defun todo-ask (lne) "Ask whether entry is more important than at LNE." | |
da2ee685 | 194 | (if (not (equal todo-prv-lne lne)) |
3cb152f9 OS |
195 | (progn |
196 | (setq todo-prv-lne lne) | |
197 | (goto-line todo-prv-lne) | |
198 | (setq todo-prv-ans (y-or-n-p (concat "More important than '" (todo-line) "'? "))) | |
199 | ) | |
200 | ) | |
201 | todo-prv-ans | |
202 | ) | |
203 | ||
da2ee685 | 204 | (defun todo-add-category (cat) "Add a new category to the TODO list." |
3cb152f9 | 205 | (interactive) |
3cb152f9 | 206 | (save-window-excursion |
da2ee685 | 207 | (setq todo-cats (cons cat todo-cats)) |
3cb152f9 | 208 | (find-file todo-file-do) |
da2ee685 OS |
209 | (widen) |
210 | (goto-char (point-min)) | |
211 | (let ((posn (search-forward "-*- mode: todo; " 17 t))) | |
212 | (if (not (null posn)) (goto-char posn)) | |
213 | (if (equal posn nil) (progn (insert "-*- mode: todo; \n") (forward-char -1)) (kill-line)) | |
3cb152f9 | 214 | ) |
da2ee685 OS |
215 | (insert (format "todo-cats: %S; -*-" todo-cats)) |
216 | (forward-char 1) | |
217 | (insert (format "%s --- %s\n--- End\n%s %s\n" todo-prefix cat todo-prefix (make-string 75 ?-))) | |
3cb152f9 | 218 | ) |
da2ee685 OS |
219 | 0 |
220 | ) | |
221 | ||
222 | (defun todo-cmd-inst () "Insert new TODO list entry." | |
223 | (interactive) | |
3cb152f9 | 224 | (beginning-of-line nil) |
da2ee685 OS |
225 | (let* ((todo-entry (concat todo-prefix " " (read-from-minibuffer "New TODO entry: "))) |
226 | (temp-catgs todo-cats) | |
a360be79 | 227 | (todo-hstry (cons 'temp-catgs (+ todo-category-number 1)))) |
da2ee685 OS |
228 | (save-window-excursion |
229 | (setq todo-category | |
230 | (read-from-minibuffer "Category: " (nth todo-category-number todo-cats) nil nil todo-hstry)) | |
231 | (let* ((ltrgt todo-category) | |
232 | (lnmbr 0) | |
233 | (ltext (car todo-cats)) | |
234 | (lrest (cdr todo-cats))) | |
235 | (setq ltext (car todo-cats)) | |
236 | (while (not (or (null lrest) (string-equal ltext ltrgt))) | |
237 | (setq ltext (car lrest)) | |
238 | (setq lrest (cdr lrest)) | |
239 | (setq lnmbr (+ 1 lnmbr)) | |
240 | ) | |
241 | (setq todo-category-number | |
242 | (if (string-equal ltext todo-category) lnmbr (todo-add-category todo-category))) | |
243 | ) | |
244 | (todo-show) | |
245 | (setq todo-prv-lne 0) | |
246 | (let* ((todo-fst 1) | |
247 | (todo-lst (+ 1 (count-lines (point-min) (point-max))))) | |
248 | (while (< todo-fst todo-lst) | |
249 | (let* ((todo-cur (/ (+ todo-fst todo-lst) 2)) | |
250 | (todo-ans (if (< todo-cur todo-lst) (todo-ask todo-cur) nil))) | |
251 | (if todo-ans | |
252 | (setq todo-lst todo-cur) | |
253 | (setq todo-fst (+ todo-cur 1))) | |
254 | ) | |
255 | ) | |
256 | (goto-line todo-fst) | |
257 | ) | |
258 | (insert (concat todo-entry "\n")) | |
259 | (forward-line -1) | |
260 | ) | |
261 | (beginning-of-line nil) | |
262 | (message "") | |
263 | ) | |
3cb152f9 OS |
264 | ) |
265 | ||
da2ee685 | 266 | (defun todo-cmd-kill () "Delete current TODO list entry." |
3cb152f9 OS |
267 | (interactive) |
268 | (if (> (count-lines (point-min) (point-max)) 0) | |
269 | (progn | |
da2ee685 OS |
270 | (let* ((todo-entry (todo-line)) |
271 | (todo-answer (y-or-n-p (concat "Permanently remove '" todo-entry "'? ")))) | |
272 | (if todo-answer | |
273 | (progn | |
274 | (delete-region (point-at-bol) (+ 1 (point-at-eol))) | |
275 | (forward-line -1) | |
276 | ) | |
277 | ) | |
278 | ) | |
279 | (message "") | |
3cb152f9 | 280 | ) |
da2ee685 | 281 | (message "No TODO list entry to delete.") |
3cb152f9 OS |
282 | ) |
283 | (beginning-of-line nil) | |
3cb152f9 OS |
284 | ) |
285 | ||
8cdc3b3d OS |
286 | (defun todo-cmd-rais () "Raise priority of current entry." |
287 | (interactive) | |
288 | (if (> (count-lines (point-min) (point-max)) 0) | |
289 | (progn | |
290 | (setq todo-entry (todo-line)) | |
da2ee685 | 291 | (delete-region (point-at-bol) (+ 1 (point-at-eol))) |
8cdc3b3d OS |
292 | (forward-line -1) |
293 | (insert (concat todo-entry "\n")) | |
da2ee685 OS |
294 | (forward-line -1) |
295 | (message "") | |
8cdc3b3d | 296 | ) |
da2ee685 | 297 | (message "No TODO list entry to raise.") |
8cdc3b3d OS |
298 | ) |
299 | (beginning-of-line nil) | |
8cdc3b3d OS |
300 | ) |
301 | ||
302 | (defun todo-cmd-lowr () "Lower priority of current entry." | |
303 | (interactive) | |
304 | (if (> (count-lines (point-min) (point-max)) 0) | |
305 | (progn | |
306 | (setq todo-entry (todo-line)) | |
da2ee685 | 307 | (delete-region (point-at-bol) (+ 1 (point-at-eol))) |
8cdc3b3d OS |
308 | (forward-line 1) |
309 | (insert (concat todo-entry "\n")) | |
da2ee685 OS |
310 | (forward-line -1) |
311 | (message "") | |
8cdc3b3d | 312 | ) |
da2ee685 | 313 | (message "No TODO list entry to raise.") |
8cdc3b3d OS |
314 | ) |
315 | (beginning-of-line nil) | |
8cdc3b3d OS |
316 | ) |
317 | ||
da2ee685 | 318 | (defun todo-cmd-file () "File away the current TODO list entry." |
3cb152f9 OS |
319 | (interactive) |
320 | (if (> (count-lines (point-min) (point-max)) 0) | |
321 | (progn | |
da2ee685 OS |
322 | (let ((time-stamp-format "%3b %2d, %y, %02I:%02M%p")) |
323 | (beginning-of-line nil) | |
a360be79 | 324 | (delete-region (point-at-bol) (search-forward todo-prefix)) |
da2ee685 OS |
325 | (insert (time-stamp-string)) |
326 | (end-of-line nil) | |
a360be79 | 327 | (insert (concat " (" (read-from-minibuffer "Comment: ") ")")) |
da2ee685 OS |
328 | (append-to-file (point-at-bol) (+ 1 (point-at-eol)) todo-file-done) |
329 | (delete-region (point-at-bol) (+ 1 (point-at-eol))) | |
330 | (forward-line -1) | |
331 | ) | |
332 | (message "") | |
3cb152f9 | 333 | ) |
da2ee685 | 334 | (message "No TODO list entry to delete.") |
3cb152f9 OS |
335 | ) |
336 | (beginning-of-line nil) | |
3cb152f9 OS |
337 | ) |
338 | ||
339 | ;; --------------------------------------------------------------------------- | |
340 | ||
da2ee685 OS |
341 | ;; utility functions: These are available in XEmacs, but not in Emacs 19.34 |
342 | ||
343 | (if (not (fboundp 'point-at-bol)) | |
344 | (defun point-at-bol () | |
345 | (save-excursion | |
346 | (beginning-of-line) | |
347 | (point)))) | |
348 | ||
349 | (if (not (fboundp 'point-at-eol)) | |
350 | (defun point-at-eol () | |
351 | (save-excursion | |
352 | (end-of-line) | |
353 | (point)))) | |
354 | ||
355 | ;; --------------------------------------------------------------------------- | |
356 | ||
a360be79 OS |
357 | (defvar todo-mode-popup-menu |
358 | (purecopy '("Todo Mode Menu" | |
359 | ["Forward item" todo-cmd-forw t] | |
360 | ["Backward item" todo-cmd-back t] | |
361 | "---" | |
362 | ["Edit item" todo-cmd-edit t] | |
363 | ["File item" todo-cmd-file t] | |
364 | ["Insert new item" todo-cmd-inst t] | |
365 | ["Kill item" todo-cmd-kill t] | |
366 | "---" | |
367 | ["Lower item priority" todo-cmd-lowr t] | |
368 | ["Raise item priority" todo-cmd-rais t] | |
369 | "---" | |
370 | ["Next item" todo-cmd-next t] | |
371 | ["Previous item" todo-cmd-prev t] | |
372 | "---" | |
373 | ["Save" todo-cmd-save t] | |
374 | "---" | |
375 | ["Quit" todo-cmd-done t] | |
376 | ) | |
377 | ) | |
378 | ) | |
379 | ||
da2ee685 OS |
380 | (defvar todo-cats nil "TODO categories.") |
381 | (defvar todo-category-number 0 "TODO category number.") | |
382 | ||
383 | (defun todo-mode () "Major mode for editing TODO lists.\n\n\\{todo-mode-map}" | |
3cb152f9 | 384 | (interactive) |
3cb152f9 OS |
385 | (setq major-mode 'todo-mode) |
386 | (setq mode-name "TODO") | |
387 | (use-local-map todo-mode-map) | |
a360be79 | 388 | (setq mode-popup-menu todo-mode-popup-menu) |
da2ee685 OS |
389 | (run-hooks 'todo-mode-hook) |
390 | ) | |
391 | ||
392 | (defun todo-show () "Show TODO list." | |
393 | (interactive) | |
394 | (find-file todo-file-do) | |
395 | (if (null todo-cats) | |
396 | (progn | |
397 | (todo-add-category "Todo") | |
398 | (goto-char (point-min)) | |
399 | (goto-char (search-forward "--- End")) | |
400 | (let ((bol (point-at-bol))) | |
401 | (forward-line 1) | |
402 | (let* ((eol (+ (point-at-eol) 1)) | |
403 | (mrkr (buffer-substring bol eol))) | |
404 | (delete-region bol eol) | |
405 | (goto-char (point-max)) | |
406 | (insert mrkr) | |
407 | ) | |
408 | ) | |
409 | (save-buffer) | |
410 | (kill-buffer (current-buffer)) | |
411 | (find-file todo-file-do) | |
412 | ) | |
413 | ) | |
7e6ed9b9 | 414 | (beginning-of-line nil) |
da2ee685 OS |
415 | (todo-cat-slct) |
416 | ) | |
3cb152f9 OS |
417 | |
418 | (provide 'todomode) | |
419 | ||
420 | ;; --------------------------------------------------------------------------- | |
421 | ||
da2ee685 | 422 | ;; todomode.el ends here |
3cb152f9 OS |
423 | |
424 | ;; --------------------------------------------------------------------------- |