Mercurial > emacs
comparison lisp/calendar/todo-mode.el @ 30028:2a636f84f3c5
Replaced with a working version, based on revision 1.34 tidied up.
author | Dave Love <fx@gnu.org> |
---|---|
date | Tue, 04 Jul 2000 11:15:24 +0000 |
parents | a37837ad882e |
children | 152ae6b57597 |
comparison
equal
deleted
inserted
replaced
30027:a37837ad882e | 30028:2a636f84f3c5 |
---|---|
1 ;; todo-mode.el -- Major mode for editing TODO list files | 1 ;; todo-mode.el -- Major mode for editing TODO list files |
2 | 2 |
3 ;; Copyright (C) 1997, 2000 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1997, 1999 Free Software Foundation, Inc. |
4 | 4 |
5 ;; Author: os10000@seidel-space.de [not clear that this works, July 2000] | 5 ;; Author: Oliver Seidel <os10000@seidel-space.de> |
6 ;; [Not clear the above works, July 2000] | |
6 ;; Created: 2 Aug 1997 | 7 ;; Created: 2 Aug 1997 |
7 ;; Version: $Id: todo-mode.el,v 1.41 2000/06/06 16:43:40 fx Exp $ | 8 ;; Version: $Id: todo-mode.el,v 1.1 1999/05/12 11:49:30 fx Exp fx $ |
8 ;; Keywords: Categorised TODO list editor, todo-mode | 9 ;; Keywords: calendar, todo |
9 | 10 |
10 ;; This file is part of GNU Emacs. | 11 ;; This file is part of GNU Emacs. |
11 | 12 |
12 ;; GNU Emacs is free software; you can redistribute it and/or modify | 13 ;; GNU Emacs is free software; you can redistribute it and/or modify |
13 ;; it under the terms of the GNU General Public License as published by | 14 ;; it under the terms of the GNU General Public License as published by |
58 ;; (autoload 'todo-insert-item "todo-mode" | 59 ;; (autoload 'todo-insert-item "todo-mode" |
59 ;; "Add TODO item." t) | 60 ;; "Add TODO item." t) |
60 ;; | 61 ;; |
61 ;; You may now enter new items by typing "M-x todo-insert-item", | 62 ;; You may now enter new items by typing "M-x todo-insert-item", |
62 ;; or enter your TODO list file by typing "M-x todo-show". | 63 ;; or enter your TODO list file by typing "M-x todo-show". |
63 ;; | |
64 ;; ------------------------------------------------------------- | |
65 ;; | |
66 ;; oh no, it doesn't work any more ... but Alex Schroeder | |
67 ;; <a.schroeder@bsiag.ch> writes: | |
68 ;; | |
69 ;; ------------------------------------------------------------- | |
70 ;; | |
71 ;; 1. Call todo-show (I called todo-insert first) | |
72 ;; 2. Add some categories (I called todo-insert) | |
73 ;; 3. Save the buffer, restart Emacs (perhaps restarting Emacs is not | |
74 ;; required) | |
75 ;; 4. Only now can you start to add entries. | |
76 ;; | |
77 ;; This is a bit cumbersome, and it should be documented. You probably | |
78 ;; | |
79 ;; ------------------------------------------------------------- | |
80 ;; | |
81 ;; and right he is. My apologies, I'll try to fix it sometime. | |
82 ;; | |
83 ;; ------------------------------------------------------------- | |
84 ;; | 64 ;; |
85 ;; The TODO list file has a special format and some auxiliary | 65 ;; The TODO list file has a special format and some auxiliary |
86 ;; information, which will be added by the todo-show function if | 66 ;; information, which will be added by the todo-show function if |
87 ;; it attempts to visit an un-initialised file. Hence it is | 67 ;; it attempts to visit an un-initialised file. Hence it is |
88 ;; recommended to use the todo-show function for the first time, | 68 ;; recommended to use the todo-show function for the first time, |
115 ;; | 95 ;; |
116 ;; Version | 96 ;; Version |
117 ;; | 97 ;; |
118 ;; Which version of todo-mode.el does this documentation refer to? | 98 ;; Which version of todo-mode.el does this documentation refer to? |
119 ;; | 99 ;; |
120 ;; $Id: todo-mode.el,v 1.41 2000/06/06 16:43:40 fx Exp $ | 100 ;; $Id: todo-mode.el,v 1.1 1999/05/12 11:49:30 fx Exp fx $ |
101 ;; | |
102 ;; Pre-Requisites | |
103 ;; | |
104 ;; This package will require the following packages to be | |
105 ;; available on the load-path: | |
106 ;; | |
107 ;; time-stamp | |
108 ;; easymenu | |
121 ;; | 109 ;; |
122 ;; Operation | 110 ;; Operation |
123 ;; | 111 ;; |
124 ;; You will have the following facilities available: | 112 ;; You will have the following facilities available: |
125 ;; | 113 ;; |
126 ;; M-x todo-show will enter the todo list screen, here type | 114 ;; M-x todo-show will enter the todo list screen, here type |
127 ;; | |
128 ;; spc will toggle the display of sub-trees | |
129 ;; | 115 ;; |
130 ;; + to go to next category | 116 ;; + to go to next category |
131 ;; - to go to previous category | 117 ;; - to go to previous category |
132 ;; d to file the current entry, including a | 118 ;; d to file the current entry, including a |
133 ;; comment and timestamp | 119 ;; comment and timestamp |
276 ;; Oliver Seidel | 262 ;; Oliver Seidel |
277 ;; (Lessingstr. 8, 65760 Eschborn, Federal Republic of Germany) | 263 ;; (Lessingstr. 8, 65760 Eschborn, Federal Republic of Germany) |
278 | 264 |
279 ;;; Code: | 265 ;;; Code: |
280 | 266 |
281 (eval-when-compile | |
282 (require 'outline) | |
283 (require 'calendar) | |
284 ;; Calendar dynamic bondage: | |
285 (defvar date) | |
286 (defvar entry)) | |
287 (autoload 'time-stamp-string "time-stamp") | |
288 | |
289 ;; User-configurable variables: | 267 ;; User-configurable variables: |
290 | 268 |
291 (defgroup todo nil | 269 (defgroup todo nil |
292 "Maintain a list of todo items." | 270 "Maintain a list of todo items." |
293 :version "21.1" | |
294 :group 'calendar) | 271 :group 'calendar) |
295 | 272 |
296 (defcustom todo-prefix "*/*" | 273 (defcustom todo-prefix "*/*" |
297 "*TODO mode prefix for entries. | 274 "*TODO mode prefix for entries. |
298 | 275 |
299 This is useful in conjunction with `calendar' and `diary' if you use | 276 This is useful in conjunction with `calendar' and `diary' if you use |
300 | 277 |
301 #include \"~/.todo-do\" | 278 #include \"~/.todo-do\" |
306 Using \"&%%(equal (calendar-current-date) date)\" instead will only | 283 Using \"&%%(equal (calendar-current-date) date)\" instead will only |
307 show and mark todo entreis for today, but may slow down processing of | 284 show and mark todo entreis for today, but may slow down processing of |
308 the diary file somewhat." | 285 the diary file somewhat." |
309 :type 'string | 286 :type 'string |
310 :group 'todo) | 287 :group 'todo) |
311 (defcustom todo-file-do "~/.todo-do" | 288 (defcustom todo-file-do "~/.todo-do" |
312 "*TODO mode list file." | 289 "*TODO mode list file." |
313 :type 'file | 290 :type 'file |
314 :group 'todo) | 291 :group 'todo) |
315 (defcustom todo-file-done "~/.todo-done" | 292 (defcustom todo-file-done "~/.todo-done" |
316 "*TODO mode archive file." | 293 "*TODO mode archive file." |
317 :type 'file | 294 :type 'file |
318 :group 'todo) | 295 :group 'todo) |
319 (defcustom todo-mode-hook nil | 296 (defcustom todo-mode-hook nil |
320 "*TODO mode hooks." | 297 "*TODO mode hooks." |
338 e.g. 8, it will stop as soon as the window size drops below that | 315 e.g. 8, it will stop as soon as the window size drops below that |
339 amount and will insert the item in the approximate centre of that | 316 amount and will insert the item in the approximate centre of that |
340 window." | 317 window." |
341 :type 'integer | 318 :type 'integer |
342 :group 'todo) | 319 :group 'todo) |
343 (defvar todo-edit-buffer " *TODO Edit*" "TODO Edit buffer name.") | 320 (defvar todo-edit-buffer " *TODO Edit*" |
321 "TODO Edit buffer name.") | |
344 (defcustom todo-file-top "~/.todo-top" | 322 (defcustom todo-file-top "~/.todo-top" |
345 "*TODO mode top priorities file. | 323 "*TODO mode top priorities file. |
346 | 324 |
347 Not in TODO format, but diary compatible. | 325 Not in TODO format, but diary compatible. |
348 Automatically generated when `todo-save-top-priorities' is non-nil." | 326 Automatically generated when `todo-save-top-priorities' is non-nil." |
362 "*Default number of priorities to print by \\[todo-print]. | 340 "*Default number of priorities to print by \\[todo-print]. |
363 0 means print all entries." | 341 0 means print all entries." |
364 :type 'integer | 342 :type 'integer |
365 :group 'todo) | 343 :group 'todo) |
366 (defcustom todo-remove-separator t | 344 (defcustom todo-remove-separator t |
367 "*Non-nil to remove category separators in \ | 345 "*Non-nil to remove category separators in\ |
368 \\[todo-top-priorities] and \\[todo-print]." | 346 \\[todo-top-priorities] and \\[todo-print]." |
369 :type 'boolean | 347 :type 'boolean |
370 :group 'todo) | 348 :group 'todo) |
371 (defcustom todo-save-top-priorities-too t | 349 (defcustom todo-save-top-priorities-too t |
372 "*Non-nil makes `todo-save' automatically save top-priorities in `todo-file-top'." | 350 "*Non-nil makes `todo-save' automatically save top-priorities in `todo-file-top'." |
375 | 353 |
376 ;; Thanks for the ISO time stamp format go to Karl Eichwalder <ke@suse.de> | 354 ;; Thanks for the ISO time stamp format go to Karl Eichwalder <ke@suse.de> |
377 ;; My format string for the appt.el package is "%3b %2d, %y, %02I:%02M%p". | 355 ;; My format string for the appt.el package is "%3b %2d, %y, %02I:%02M%p". |
378 ;; | 356 ;; |
379 (defcustom todo-time-string-format | 357 (defcustom todo-time-string-format |
380 "%04y-%02m-%02d %02H:%02M" | 358 "%:y-%02m-%02d %02H:%02M" |
381 "*TODO mode time string format for done entries. | 359 "*TODO mode time string format for done entries. |
382 For details see the variable `time-stamp-format'." | 360 For details see the variable `time-stamp-format'." |
383 :type 'string | 361 :type 'string |
384 :group 'todo) | 362 :group 'todo) |
385 | 363 |
389 :group 'todo) | 367 :group 'todo) |
390 (defcustom todo-initials (or (getenv "INITIALS") (user-login-name)) | 368 (defcustom todo-initials (or (getenv "INITIALS") (user-login-name)) |
391 "*Initials of todo item author." | 369 "*Initials of todo item author." |
392 :type 'string | 370 :type 'string |
393 :group 'todo) | 371 :group 'todo) |
372 | |
373 (autoload 'time-stamp-string "time-stamp") | |
394 | 374 |
395 (defun todo-entry-timestamp-initials () | 375 (defun todo-entry-timestamp-initials () |
396 "Prepend timestamp and your initials to the head of a TODO entry." | 376 "Prepend timestamp and your initials to the head of a TODO entry." |
397 (let ((time-stamp-format todo-time-string-format)) | 377 (let ((time-stamp-format todo-time-string-format)) |
398 (concat (time-stamp-string) " " todo-initials ": "))) | 378 (concat (time-stamp-string) " " todo-initials ": "))) |
399 | 379 |
380 ;; --------------------------------------------------------------------------- | |
381 | |
400 ;; Set up some helpful context ... | 382 ;; Set up some helpful context ... |
401 | 383 |
402 (defvar todo-categories nil | 384 (defvar todo-categories nil |
403 "TODO categories.") | 385 "TODO categories.") |
386 | |
404 (defvar todo-cats nil | 387 (defvar todo-cats nil |
405 "Old variable for holding the TODO categories. | 388 "Old variable for holding the TODO categories. |
406 Use `todo-categories' instead.") | 389 Use `todo-categories' instead.") |
407 (defvar todo-previous-line 0 | 390 |
391 (defvar todo-previous-line 0 | |
408 "Previous line asked about.") | 392 "Previous line asked about.") |
409 (defvar todo-previous-answer 0 | 393 |
394 (defvar todo-previous-answer 0 | |
410 "Previous answer got.") | 395 "Previous answer got.") |
411 (defvar todo-category-number 0 | |
412 "TODO category number.") | |
413 | |
414 (defvar todo-category-sep (make-string 75 ?-) | |
415 "Category separator.") | |
416 (defvar todo-category-beg " --- " | |
417 "Category start separator to be prepended onto category name.") | |
418 (defvar todo-category-end "--- End" | |
419 "Separator after a category.") | |
420 (defvar todo-header "-*- mode: todo; " | |
421 "Header of todo files.") | |
422 | |
423 ;; --------------------------------------------------------------------------- | |
424 | 396 |
425 (defvar todo-mode-map | 397 (defvar todo-mode-map |
426 (let ((map (make-keymap))) | 398 (let ((map (make-keymap))) |
427 (suppress-keymap map t) | 399 (suppress-keymap map t) |
428 (define-key map "?" 'todo-help) | |
429 (define-key map " " 'todo-hide-show-subtree) | |
430 (define-key map "+" 'todo-forward-category) | 400 (define-key map "+" 'todo-forward-category) |
431 (define-key map "-" 'todo-backward-category) | 401 (define-key map "-" 'todo-backward-category) |
432 (define-key map "d" 'todo-file-item) ;done/delete | 402 (define-key map "d" 'todo-file-item) ;done/delete |
433 (define-key map "e" 'todo-edit-item) | 403 (define-key map "e" 'todo-edit-item) |
434 (define-key map "E" 'todo-edit-multiline) | 404 (define-key map "E" 'todo-edit-multiline) |
447 (define-key map "S" 'todo-save-top-priorities) | 417 (define-key map "S" 'todo-save-top-priorities) |
448 (define-key map "t" 'todo-top-priorities) | 418 (define-key map "t" 'todo-top-priorities) |
449 map) | 419 map) |
450 "TODO mode keymap.") | 420 "TODO mode keymap.") |
451 | 421 |
452 (defun todo-position (item list) | 422 (defvar todo-category-number 0 "TODO category number.") |
453 "Return the position of the element in LIST testing `equal' to ITEM. | 423 |
454 Return nil if ITEM not found." | 424 (defvar todo-tmp-buffer-name " *todo tmp*") |
455 (let ((pos 0) | 425 |
456 found) | 426 (defvar todo-category-sep (make-string 75 ?-) |
457 (while list | 427 "Category separator.") |
458 (if (equal item (pop list)) | 428 |
459 (setq list nil | 429 (defvar todo-category-beg " --- " |
460 found pos) | 430 "Category start separator to be prepended onto category name.") |
461 (setq pos (1+ pos)))) | 431 |
462 found)) | 432 (defvar todo-category-end "--- End" |
433 "Separator after a category.") | |
434 | |
435 (defvar todo-header "-*- mode: todo; " | |
436 "Header of todo files.") | |
437 | |
438 ;; --------------------------------------------------------------------------- | |
463 | 439 |
464 (defun todo-category-select () | 440 (defun todo-category-select () |
465 "Make TODO mode display the current category correctly." | 441 "Make TODO mode display the current category correctly." |
466 (let ((name (nth todo-category-number todo-categories))) | 442 (let ((name (nth todo-category-number todo-categories))) |
467 (setq mode-line-buffer-identification | 443 (setq mode-line-buffer-identification |
444 ;; (concat "Category: " name)) | |
468 (concat "Category: " (format "%18s" name))) | 445 (concat "Category: " (format "%18s" name))) |
469 (widen) | 446 (widen) |
470 (goto-char (point-min)) | 447 (goto-char (point-min)) |
471 (search-forward-regexp | 448 (search-forward-regexp |
472 (concat "^" | 449 (concat "^" |
476 (search-forward-regexp (concat "^" todo-category-end)) | 453 (search-forward-regexp (concat "^" todo-category-end)) |
477 (narrow-to-region begin (line-beginning-position)) | 454 (narrow-to-region begin (line-beginning-position)) |
478 (goto-char (point-min))))) | 455 (goto-char (point-min))))) |
479 (defalias 'todo-cat-slct 'todo-category-select) | 456 (defalias 'todo-cat-slct 'todo-category-select) |
480 | 457 |
481 (defun todo-help () "Show TODO mode help." | |
482 (interactive) | |
483 (describe-function 'todo-mode)) | |
484 | |
485 (defun todo-hide-show-subtree () | |
486 "Hide or Show subtrees in the TODO list." | |
487 (interactive) | |
488 (save-excursion | |
489 (end-of-line) | |
490 (if (outline-visible) | |
491 (hide-subtree) | |
492 (show-subtree)))) | |
493 | |
494 (defun todo-forward-category () | 458 (defun todo-forward-category () |
495 "Go forward to TODO list of next category." | 459 "Go forward to TODO list of next category." |
496 (interactive) | 460 (interactive) |
497 (setq todo-category-number | 461 (setq todo-category-number |
498 (mod (1+ todo-category-number) (length todo-categories))) | 462 (mod (1+ todo-category-number) (length todo-categories))) |
523 nil 'goto-end count) | 487 nil 'goto-end count) |
524 (beginning-of-line) | 488 (beginning-of-line) |
525 (message "")) | 489 (message "")) |
526 (defalias 'todo-cmd-next 'todo-forward-item) | 490 (defalias 'todo-cmd-next 'todo-forward-item) |
527 | 491 |
528 (defun todo-save () "Save the TODO list." | 492 (defun todo-save () |
493 "Save the TODO list." | |
529 (interactive) | 494 (interactive) |
530 (save-buffer) | 495 (save-buffer) |
531 (if todo-save-top-priorities-too (todo-save-top-priorities))) | 496 (if todo-save-top-priorities-too (todo-save-top-priorities)) |
497 ) | |
532 (defalias 'todo-cmd-save 'todo-save) | 498 (defalias 'todo-cmd-save 'todo-save) |
533 | 499 |
534 (defun todo-quit () "Done with TODO list for now." | 500 (defun todo-quit () |
501 "Done with TODO list for now." | |
535 (interactive) | 502 (interactive) |
536 (widen) | 503 (widen) |
537 (todo-save) | 504 (todo-save) |
538 (message "") | 505 (message "") |
539 (bury-buffer)) | 506 (bury-buffer)) |
540 (defalias 'todo-cmd-done 'todo-quit) | 507 (defalias 'todo-cmd-done 'todo-quit) |
541 | 508 |
542 (defun todo-edit-item () "Edit current TODO list entry." | 509 (defun todo-edit-item () |
510 "Edit current TODO list entry." | |
543 (interactive) | 511 (interactive) |
544 (let ((item (todo-item-string))) | 512 (let ((item (todo-item-string))) |
545 (if (todo-string-multiline-p item) | 513 (if (todo-string-multiline-p item) |
546 (todo-edit-multiline) | 514 (todo-edit-multiline) |
547 (let ((new (read-from-minibuffer "Edit: " item))) | 515 (let ((new (read-from-minibuffer "Edit: " item))) |
548 (todo-remove-item) | 516 (todo-remove-item) |
549 (insert new ?\n) | 517 (insert new "\n") |
550 (todo-backward-item) | 518 (todo-backward-item) |
551 (message ""))))) | 519 (message ""))))) |
552 (defalias 'todo-cmd-edit 'todo-edit-item) | 520 (defalias 'todo-cmd-edit 'todo-edit-item) |
553 | 521 |
554 (defun todo-edit-multiline () | 522 (defun todo-edit-multiline () |
555 "Set up a buffer for editing a multiline TODO list entry." | 523 "Set up a buffer for editing a multiline TODO list entry." |
556 (interactive) | 524 (interactive) |
557 (let ((buffer-name (generate-new-buffer-name todo-edit-buffer))) | 525 (let ((buffer-name (generate-new-buffer-name todo-edit-buffer))) |
558 (switch-to-buffer | 526 (switch-to-buffer |
559 (make-indirect-buffer | 527 (make-indirect-buffer |
560 (find-buffer-visiting todo-file-do) buffer-name)) | 528 (file-name-nondirectory todo-file-do) buffer-name)) |
561 (message "To exit, simply kill this buffer and return to list.") | 529 (message "To exit, simply kill this buffer and return to list.") |
562 (todo-edit-mode) | 530 (todo-edit-mode) |
563 (narrow-to-region (todo-item-start) (todo-item-end)))) | 531 (narrow-to-region (todo-item-start) (todo-item-end)))) |
564 | 532 |
533 ;;;### autoload | |
565 (defun todo-add-category (cat) | 534 (defun todo-add-category (cat) |
566 "Add new category CAT to the TODO list." | 535 "Add new category CAT to the TODO list." |
567 (interactive "sCategory: ") | 536 (interactive "sCategory: ") |
568 (save-window-excursion | 537 (save-window-excursion |
569 (add-to-list 'todo-categories cat) | 538 (setq todo-categories (cons cat todo-categories)) |
570 (find-file todo-file-do) | 539 (find-file todo-file-do) |
571 (widen) | 540 (widen) |
572 (goto-char (point-min)) | 541 (goto-char (point-min)) |
573 (let ((posn (search-forward "-*- mode: todo; " 17 t))) | 542 (let ((posn (search-forward "-*- mode: todo; " 17 t))) |
574 (if posn | 543 (if (not (null posn)) (goto-char posn)) |
544 (if (equal posn nil) | |
575 (progn | 545 (progn |
576 (goto-char posn) | 546 (insert "-*- mode: todo; \n") |
577 (kill-line)) | 547 (forward-char -1)) |
578 (insert "-*- mode: todo; \n") | 548 (kill-line))) |
579 (backward-char))) | |
580 (insert (format "todo-categories: %S; -*-" todo-categories)) | 549 (insert (format "todo-categories: %S; -*-" todo-categories)) |
581 (forward-char) | 550 (forward-char 1) |
582 (insert (format "%s%s%s\n%s\n%s %s\n" | 551 (insert (format "%s%s%s\n%s\n%s %s\n" |
583 todo-prefix todo-category-beg cat | 552 todo-prefix todo-category-beg cat |
584 todo-category-end | 553 todo-category-end |
585 todo-prefix todo-category-sep)) | 554 todo-prefix todo-category-sep))) |
586 (save-buffer)) | |
587 0) | 555 0) |
588 | 556 |
557 ;;;### autoload | |
589 (defun todo-add-item-non-interactively (new-item category) | 558 (defun todo-add-item-non-interactively (new-item category) |
590 "Insert NEW-ITEM in TODO list as a new entry in CATEGORY." | 559 "Insert NEW-ITEM in TODO list as a new entry in CATEGORY." |
591 (save-excursion | 560 (save-excursion |
592 (todo-show)) | 561 (todo-show)) |
593 (save-excursion | 562 (save-excursion |
594 (if (string= "" category) | 563 (if (string= "" category) |
595 (setq category (nth todo-category-number todo-categories))) | 564 (setq category (nth todo-category-number todo-categories))) |
596 (setq todo-category-number | 565 (let ((cat-exists (member category todo-categories))) |
597 (or (todo-position category todo-categories) | 566 (setq todo-category-number |
598 (todo-add-category category))) | 567 (if cat-exists |
568 (- (length todo-categories) (length cat-exists)) | |
569 (todo-add-category category)))) | |
599 (todo-show) | 570 (todo-show) |
600 (setq todo-previous-line 0) | 571 (setq todo-previous-line 0) |
601 (let ((top 1) | 572 (let ((top 1) |
602 (bottom (1+ (count-lines (point-min) (point-max))))) | 573 (bottom (1+ (count-lines (point-min) (point-max))))) |
603 (while (> (- bottom top) todo-insert-threshold) | 574 (while (> (- bottom top) todo-insert-threshold) |
604 (let* ((current (/ (+ top bottom) 2)) | 575 (let* ((current (/ (+ top bottom) 2)) |
605 (answer (if (< current bottom) | 576 (answer (if (< current bottom) |
606 (todo-more-important-p current)))) | 577 (todo-more-important-p current) nil))) |
607 (if answer | 578 (if answer |
608 (setq bottom current) | 579 (setq bottom current) |
609 (setq top (1+ current))))) | 580 (setq top (1+ current))))) |
610 (setq top (/ (+ top bottom) 2)) | 581 (setq top (/ (+ top bottom) 2)) |
611 ;; goto-line doesn't have the desired behavior in a narrowed buffer | 582 ;; goto-line doesn't have the desired behavior in a narrowed buffer |
612 (goto-char (point-min)) | 583 (goto-char (point-min)) |
613 (forward-line (1- top))) | 584 (forward-line (1- top))) |
614 (insert new-item ?\n) | 585 (insert new-item "\n") |
615 (todo-backward-item) | 586 (todo-backward-item) |
616 (progn ;;; horrible os10000 hack to make items appear when inserting into empty buffer | |
617 (widen) | |
618 (show-all) | |
619 (todo-forward-category) | |
620 (todo-backward-category)) | |
621 (todo-save) | 587 (todo-save) |
622 (message ""))) | 588 (message ""))) |
623 | 589 |
624 ;;;###autoload | 590 ;;;### autoload |
625 (defun todo-insert-item (arg) | 591 (defun todo-insert-item (arg) |
626 "Insert new TODO list entry. | 592 "Insert new TODO list entry. |
627 With a prefix argument solicit the category, otherwise use the current | 593 With a prefix argument solicit the category, otherwise use the current |
628 category." | 594 category." |
629 (interactive "P") | 595 (interactive "P") |
638 (history (cons 'categories (1+ todo-category-number))) | 604 (history (cons 'categories (1+ todo-category-number))) |
639 (current-category (nth todo-category-number todo-categories)) | 605 (current-category (nth todo-category-number todo-categories)) |
640 (category | 606 (category |
641 (if arg | 607 (if arg |
642 current-category | 608 current-category |
643 (completing-read | 609 (completing-read (concat "Category [" current-category "]: ") |
644 (concat "Category [" current-category "]: ") | 610 (todo-category-alist) nil nil nil |
645 (todo-category-alist) nil nil nil history current-category)))) | 611 history current-category)))) |
646 (todo-add-item-non-interactively new-item category)))) | 612 (todo-add-item-non-interactively new-item category)))) |
647 | 613 |
648 (defalias 'todo-cmd-inst 'todo-insert-item) | 614 (defalias 'todo-cmd-inst 'todo-insert-item) |
649 | 615 |
616 ;;;### autoload | |
650 (defun todo-insert-item-here () | 617 (defun todo-insert-item-here () |
651 "Insert new TODO list entry under the cursor." | 618 "Insert new TODO list entry under the cursor." |
652 (interactive "") | 619 (interactive "") |
653 (save-excursion | 620 (save-excursion |
654 (if (not (string-equal mode-name "TODO")) (todo-show)) | 621 (if (not (string-equal mode-name "TODO")) (todo-show)) |
670 (setq todo-previous-answer | 637 (setq todo-previous-answer |
671 (y-or-n-p (concat "More important than '" item "'? ")))))) | 638 (y-or-n-p (concat "More important than '" item "'? ")))))) |
672 todo-previous-answer) | 639 todo-previous-answer) |
673 (defalias 'todo-ask-p 'todo-more-important-p) | 640 (defalias 'todo-ask-p 'todo-more-important-p) |
674 | 641 |
675 (defun todo-delete-item () "Delete current TODO list entry." | 642 (defun todo-delete-item () |
643 "Delete current TODO list entry." | |
676 (interactive) | 644 (interactive) |
677 (if (> (count-lines (point-min) (point-max)) 0) | 645 (if (> (count-lines (point-min) (point-max)) 0) |
678 (let* ((todo-entry (todo-item-string-start)) | 646 (let* ((todo-entry (todo-item-string-start)) |
679 (todo-answer (y-or-n-p (concat "Permanently remove '" | 647 (todo-answer (y-or-n-p (concat "Permanently remove '" |
680 todo-entry "'? ")))) | 648 todo-entry "'? ")))) |
681 (when todo-answer | 649 (if todo-answer |
682 (todo-remove-item) | 650 (progn |
683 (todo-backward-item)) | 651 (todo-remove-item) |
652 (todo-backward-item))) | |
684 (message "")) | 653 (message "")) |
685 (error "No TODO list entry to delete"))) | 654 (error "No TODO list entry to delete"))) |
686 (defalias 'todo-cmd-kill 'todo-delete-item) | 655 (defalias 'todo-cmd-kill 'todo-delete-item) |
687 | 656 |
688 (defun todo-raise-item () "Raise priority of current entry." | 657 (defun todo-raise-item () |
658 "Raise priority of current entry." | |
689 (interactive) | 659 (interactive) |
690 (if (> (count-lines (point-min) (point)) 0) | 660 (if (> (count-lines (point-min) (point)) 0) |
691 (let ((item (todo-item-string))) | 661 (let ((item (todo-item-string))) |
692 (todo-remove-item) | 662 (todo-remove-item) |
693 (todo-backward-item) | 663 (todo-backward-item) |
694 (save-excursion | 664 (save-excursion |
695 (insert item ?\n)) | 665 (insert item "\n")) |
696 (message "")) | 666 (message "")) |
697 (error "No TODO list entry to raise"))) | 667 (error "No TODO list entry to raise"))) |
698 (defalias 'todo-cmd-raise 'todo-raise-item) | 668 (defalias 'todo-cmd-rais 'todo-raise-item) |
699 | 669 |
700 (defun todo-lower-item () "Lower priority of current entry." | 670 (defun todo-lower-item () |
671 "Lower priority of current entry." | |
701 (interactive) | 672 (interactive) |
702 (if (> (count-lines (point) (point-max)) 1) | 673 (if (> (count-lines (point) (point-max)) 1) |
703 ;; Assume there is a final newline | 674 ;; Assume there is a final newline |
704 (let ((item (todo-item-string))) | 675 (let ((item (todo-item-string))) |
705 (todo-remove-item) | 676 (todo-remove-item) |
706 (todo-forward-item) | 677 (todo-forward-item) |
707 (save-excursion | 678 (save-excursion |
708 (insert item ?\n)) | 679 (insert item "\n")) |
709 (message "")) | 680 (message "")) |
710 (error "No TODO list entry to lower"))) | 681 (error "No TODO list entry to lower"))) |
711 (defalias 'todo-cmd-lowr 'todo-lower-item) | 682 (defalias 'todo-cmd-lowr 'todo-lower-item) |
712 | 683 |
713 (defun todo-file-item (&optional comment) | 684 (defun todo-file-item (&optional comment) |
714 "File the current TODO list entry away, annotated with an optional COMMENT." | 685 "File the current TODO list entry away, annotated with an optional COMMENT." |
715 (interactive "sComment: ") | 686 (interactive "sComment: ") |
716 (or (> (count-lines (point-min) (point-max)) 0) | 687 (or (> (count-lines (point-min) (point-max)) 0) |
717 (error "No TODO list entry to file away")) | 688 (error "No TODO list entry to file away")) |
718 (let ((time-stamp-format todo-time-string-format)) | 689 (let ((time-stamp-format todo-time-string-format)) |
719 (when (and comment (> (length comment) 0)) | 690 (if (and comment (> (length comment) 0)) |
720 (goto-char (todo-item-end)) | 691 (progn |
721 (insert | 692 (goto-char (todo-item-end)) |
722 (if (save-excursion (beginning-of-line) | 693 (insert |
723 (looking-at (regexp-quote todo-prefix))) | 694 (if (save-excursion (beginning-of-line) |
724 " " | 695 (looking-at (regexp-quote todo-prefix))) |
725 "\n\t") | 696 " " |
726 "(" comment ")")) | 697 "\n\t") |
698 "(" comment ")"))) | |
727 (goto-char (todo-item-end)) | 699 (goto-char (todo-item-end)) |
728 (insert " [" (nth todo-category-number todo-categories) "]") | 700 (insert " [" (nth todo-category-number todo-categories) "]") |
729 (goto-char (todo-item-start)) | 701 (goto-char (todo-item-start)) |
730 (let ((temp-point (point))) | 702 (let ((temp-point (point))) |
731 (if (looking-at (regexp-quote todo-prefix)) | 703 (if (looking-at (regexp-quote todo-prefix)) |
740 | 712 |
741 ;; --------------------------------------------------------------------------- | 713 ;; --------------------------------------------------------------------------- |
742 | 714 |
743 ;; Utility functions: | 715 ;; Utility functions: |
744 | 716 |
717 | |
718 ;;;###autoload | |
745 (defun todo-top-priorities (&optional nof-priorities category-pr-page) | 719 (defun todo-top-priorities (&optional nof-priorities category-pr-page) |
746 "List top priorities for each category. | 720 "List top priorities for each category. |
747 | 721 |
748 Number of entries for each category is given by NOF-PRIORITIES which | 722 Number of entries for each category is given by NOF-PRIORITIES which |
749 defaults to \'todo-show-priorities\'. | 723 defaults to \'todo-show-priorities\'. |
753 | 727 |
754 (interactive "P") | 728 (interactive "P") |
755 (or nof-priorities (setq nof-priorities todo-show-priorities)) | 729 (or nof-priorities (setq nof-priorities todo-show-priorities)) |
756 (if (listp nof-priorities) ;universal argument | 730 (if (listp nof-priorities) ;universal argument |
757 (setq nof-priorities (car nof-priorities))) | 731 (setq nof-priorities (car nof-priorities))) |
758 (let ((todo-print-buffer-name " *todo-tmp*") | 732 (let ((todo-print-buffer-name "*Tmp*") |
759 ;;(todo-print-category-number 0) | 733 ;;(todo-print-category-number 0) |
760 (todo-category-break (if category-pr-page "" "")) | 734 (todo-category-break (if category-pr-page "" "")) |
761 (cat-end | 735 (cat-end |
762 (concat | 736 (concat |
763 (if todo-remove-separator | 737 (if todo-remove-separator |
770 (save-restriction | 744 (save-restriction |
771 (widen) | 745 (widen) |
772 (copy-to-buffer todo-print-buffer-name (point-min) (point-max)) | 746 (copy-to-buffer todo-print-buffer-name (point-min) (point-max)) |
773 (set-buffer todo-print-buffer-name) | 747 (set-buffer todo-print-buffer-name) |
774 (goto-char (point-min)) | 748 (goto-char (point-min)) |
775 (when (re-search-forward (regexp-quote todo-header) nil t) | 749 (if (re-search-forward (regexp-quote todo-header) nil t) |
776 (beginning-of-line 1) | 750 (progn |
777 (kill-line)) ;Remove mode line | 751 (beginning-of-line 1) |
752 (kill-line))) ;Remove mode line | |
778 (while (re-search-forward ;Find category start | 753 (while (re-search-forward ;Find category start |
779 (regexp-quote (concat todo-prefix todo-category-beg)) | 754 (regexp-quote (concat todo-prefix todo-category-beg)) |
780 nil t) | 755 nil t) |
781 (setq beg (+ (line-end-position) 1)) ;Start of first entry. | 756 (setq beg (+ (line-end-position) 1)) ;Start of first entry. |
782 (re-search-forward cat-end nil t) | 757 (re-search-forward cat-end nil t) |
783 (setq end (match-beginning 0)) | 758 (setq end (match-beginning 0)) |
784 (replace-match todo-category-break) | 759 (replace-match todo-category-break) |
785 (narrow-to-region beg end) ;In case we have too few entries. | 760 (narrow-to-region beg end) ;In case we have too few entries. |
786 (goto-char (point-min)) | 761 (goto-char (point-min)) |
787 (if (= 0 nof-priorities) ;Traverse entries. | 762 (if (= 0 nof-priorities) ;Traverse entries. |
788 (goto-char end) ;All entries | 763 (goto-char end) ;All entries |
789 (todo-forward-item nof-priorities)) | 764 (todo-forward-item nof-priorities)) |
790 (setq beg (point)) | 765 (setq beg (point)) |
791 (delete-region beg end) | 766 (delete-region beg end) |
792 (widen)) | 767 (widen)) |
793 (and (looking-at "") (replace-match "")) ;Remove trailing form-feed. | 768 (and (looking-at "") (replace-match "")) ;Remove trailing form-feed. |
798 ;; Else we could have used pop-to-buffer. | 773 ;; Else we could have used pop-to-buffer. |
799 (display-buffer todo-print-buffer-name) | 774 (display-buffer todo-print-buffer-name) |
800 (message "Type C-x 1 to remove %s window. M-C-v to scroll the help." | 775 (message "Type C-x 1 to remove %s window. M-C-v to scroll the help." |
801 todo-print-buffer-name))) | 776 todo-print-buffer-name))) |
802 | 777 |
778 ;;;###autoload | |
803 (defun todo-save-top-priorities (&optional nof-priorities) | 779 (defun todo-save-top-priorities (&optional nof-priorities) |
804 "Save top priorities for each category in `todo-file-top'. | 780 "Save top priorities for each category in `todo-file-top'. |
805 | 781 |
806 Number of entries for each category is given by NOF-PRIORITIES which | 782 Number of entries for each category is given by NOF-PRIORITIES which |
807 defaults to `todo-show-priorities'." | 783 defaults to `todo-show-priorities'." |
808 (interactive "P") | 784 (interactive "P") |
809 (with-temp-buffer | 785 (save-window-excursion |
810 (todo-top-priorities nof-priorities) | 786 (save-excursion |
811 (write-file todo-file-top))) | 787 (save-restriction |
788 (todo-top-priorities nof-priorities) | |
789 (set-buffer todo-tmp-buffer-name) | |
790 (write-file todo-file-top) | |
791 (kill-this-buffer))))) | |
812 | 792 |
813 ;;;###autoload | 793 ;;;###autoload |
814 (defun todo-print (&optional category-pr-page) | 794 (defun todo-print (&optional category-pr-page) |
815 "Print todo summary using `todo-print-function'. | 795 "Print todo summary using `todo-print-function'. |
816 If CATEGORY-PR-PAGE is non-nil, a page separator \'^L\' is inserted | 796 If CATEGORY-PR-PAGE is non-nil, a page separator `^L' is inserted |
817 between each category. | 797 between each category. |
818 | 798 |
819 Number of entries for each category is given by | 799 Number of entries for each category is given by `todo-print-priorities'." |
820 \'todo-print-priorities\'." | |
821 (interactive "P") | 800 (interactive "P") |
822 (with-temp-buffer | 801 (save-window-excursion |
823 (todo-top-priorities todo-print-priorities | 802 (save-excursion |
803 (save-restriction | |
804 (todo-top-priorities todo-print-priorities | |
824 category-pr-page) | 805 category-pr-page) |
825 (funcall todo-print-function) | 806 (set-buffer todo-tmp-buffer-name) |
826 (message "Todo printing done."))) | 807 (and (funcall todo-print-function) |
808 (kill-this-buffer)) | |
809 (message "Todo printing done."))))) | |
827 | 810 |
828 (defun todo-jump-to-category () | 811 (defun todo-jump-to-category () |
829 "Jump to a category. Default is previous category." | 812 "Jump to a category. Default is previous category." |
830 (interactive) | 813 (interactive) |
831 (let* ((categories todo-categories) | 814 (let* ((categories todo-categories) |
832 (history (cons 'categories (1+ todo-category-number))) | 815 (history (cons 'categories (1+ todo-category-number))) |
816 (default (nth todo-category-number todo-categories)) | |
833 (category (completing-read | 817 (category (completing-read |
834 (concat "Category [" | 818 (concat "Category [" default "]: ") |
835 (nth todo-category-number todo-categories) "]: ") | 819 (todo-category-alist) nil nil nil history default))) |
836 (todo-category-alist) nil nil nil history))) | |
837 (if (string= "" category) | 820 (if (string= "" category) |
838 (setq category (nth todo-category-number todo-categories))) | 821 (setq category (nth todo-category-number todo-categories))) |
839 (setq todo-category-number | 822 (setq todo-category-number |
840 (or (todo-position category todo-categories) | 823 (if (member category todo-categories) |
841 (todo-add-category category))) | 824 (- (length todo-categories) |
825 (length (member category todo-categories))) | |
826 (todo-add-category category))) | |
842 (todo-show))) | 827 (todo-show))) |
843 | 828 |
844 (defun todo-line-string () | 829 (defun todo-line-string () |
845 "Return current line in buffer as a string." | 830 "Return current line in buffer as a string." |
846 (buffer-substring (line-beginning-position) (line-end-position))) | 831 (buffer-substring (line-beginning-position) (line-end-position))) |
872 | 857 |
873 (defun todo-remove-item () | 858 (defun todo-remove-item () |
874 "Delete the current entry from the TODO list." | 859 "Delete the current entry from the TODO list." |
875 (delete-region (todo-item-start) (1+ (todo-item-end)))) | 860 (delete-region (todo-item-start) (1+ (todo-item-end)))) |
876 | 861 |
877 (defun todo-item-string () "Return current TODO list entry as a string." | 862 (defun todo-item-string () |
863 "Return current TODO list entry as a string." | |
878 (buffer-substring (todo-item-start) (todo-item-end))) | 864 (buffer-substring (todo-item-start) (todo-item-end))) |
879 | 865 |
880 (defun todo-string-count-lines (string) | 866 (defun todo-string-count-lines (string) |
881 "Return the number of lines STRING spans." | 867 "Return the number of lines STRING spans." |
882 (length (split-string string "\n"))) | 868 (length (split-string string "\n"))) |
889 "Generate an alist for use in `completing-read' from `todo-categories'." | 875 "Generate an alist for use in `completing-read' from `todo-categories'." |
890 (mapcar #'list todo-categories)) | 876 (mapcar #'list todo-categories)) |
891 | 877 |
892 ;; --------------------------------------------------------------------------- | 878 ;; --------------------------------------------------------------------------- |
893 | 879 |
894 (easy-menu-define | 880 (easy-menu-define todo-menu todo-mode-map "Todo Menu" |
895 todo-menu todo-mode-map "Todo Menu" | 881 '("Todo" |
896 '("Todo" | 882 ["Next category" todo-forward-category t] |
897 ["Next category" todo-forward-category t] | 883 ["Previous category" todo-backward-category t] |
898 ["Previous category" todo-backward-category t] | 884 ["Jump to category" todo-jump-to-category t] |
899 ["Jump to category" todo-jump-to-category t] | 885 ["Show top priority items" todo-top-priorities t] |
900 ["Show top priority items" todo-top-priorities t] | 886 ["Print categories" todo-print t] |
901 ["Print categories" todo-print t] | 887 "---" |
902 "---" | 888 ["Edit item" todo-edit-item t] |
903 ["Edit item" todo-edit-item t] | 889 ["File item" todo-file-item t] |
904 ["File item" todo-file-item t] | 890 ["Insert new item" todo-insert-item t] |
905 ["Insert new item" todo-insert-item t] | 891 ["Insert item here" todo-insert-item-here t] |
906 ["Insert item here" todo-insert-item-here t] | 892 ["Kill item" todo-delete-item t] |
907 ["Kill item" todo-delete-item t] | 893 "---" |
908 "---" | 894 ["Lower item priority" todo-lower-item t] |
909 ["Lower item priority" todo-lower-item t] | 895 ["Raise item priority" todo-raise-item t] |
910 ["Raise item priority" todo-raise-item t] | 896 "---" |
911 "---" | 897 ["Next item" todo-forward-item t] |
912 ["Next item" todo-forward-item t] | 898 ["Previous item" todo-backward-item t] |
913 ["Previous item" todo-backward-item t] | 899 "---" |
914 "---" | 900 ["Save" todo-save t] |
915 ["Save" todo-save t] | 901 ["Save Top Priorities" todo-save-top-priorities t] |
916 ["Save Top Priorities" todo-save-top-priorities t] | 902 "---" |
917 "---" | 903 ["Quit" todo-quit t] |
918 ["Quit" todo-quit t] | 904 )) |
919 )) | |
920 | 905 |
921 ;; As calendar reads .todo-do before todo-mode is loaded. | 906 ;; As calendar reads .todo-do before todo-mode is loaded. |
922 ;;;###autoload | 907 ;;;### autoload |
923 (defun todo-mode () | 908 (defun todo-mode () |
924 "Major mode for editing TODO lists. | 909 "Major mode for editing TODO lists. |
925 | 910 |
926 \\{todo-mode-map}" | 911 \\{todo-mode-map}" |
927 (interactive) | 912 (interactive) |
928 (setq major-mode 'todo-mode) | 913 (setq major-mode 'todo-mode) |
929 (setq mode-name "TODO") | 914 (setq mode-name "TODO") |
930 (use-local-map todo-mode-map) | 915 (use-local-map todo-mode-map) |
931 (easy-menu-add todo-menu) | 916 (easy-menu-add todo-menu) |
932 (setq fill-prefix "\t\t") | |
933 (let ((prefix (regexp-quote todo-prefix))) | |
934 (setq paragraph-separate prefix) | |
935 (setq outline-regexp prefix)) | |
936 (outline-minor-mode 1) | |
937 (goto-char (point-min)) | |
938 (outline-next-heading) ; get past -*- line | |
939 (hide-other) | |
940 (auto-fill-mode 1) | |
941 (run-hooks 'todo-mode-hook)) | 917 (run-hooks 'todo-mode-hook)) |
942 | 918 |
919 (eval-when-compile | |
920 (defvar date) | |
921 (defvar entry)) | |
922 | |
943 ;; Read about this function in the setup instructions above! | 923 ;; Read about this function in the setup instructions above! |
944 ;;;###autoload | 924 ;;;### autoload |
945 (defun todo-cp () | 925 (defun todo-cp () |
946 "Make a diary entry appear only in the current date's diary." | 926 "Make a diary entry appear only in the current date's diary." |
947 (if (equal (calendar-current-date) date) | 927 (if (equal (calendar-current-date) date) |
948 entry)) | 928 entry)) |
949 | 929 |
950 (defun todo-edit-mode () | 930 (define-derived-mode todo-edit-mode text-mode "TODO Edit" |
951 "Major mode for editing items in the TODO list. | 931 "Major mode for editing items in the TODO list. |
952 | 932 |
953 \\{todo-edit-mode-map}" | 933 \\{todo-edit-mode-map}") |
954 (text-mode) | 934 |
955 (setq major-mode 'todo-edit-mode) | 935 ;;;### autoload |
956 (setq mode-name "TODO Edit") | |
957 (run-hooks 'todo-edit-mode-hook)) | |
958 | |
959 ;;;###autoload | |
960 (defun todo-show () | 936 (defun todo-show () |
961 "Show TODO list." | 937 "Show TODO list." |
962 (interactive) | 938 (interactive) |
963 (if (file-exists-p todo-file-do) | 939 (if (file-exists-p todo-file-do) |
964 (find-file todo-file-do) | 940 (find-file todo-file-do) |
965 (todo-initial-setup)) | 941 (todo-initial-setup)) |
966 (unless todo-categories | 942 (if (null todo-categories) |
967 (if (null todo-cats) | 943 (if (null todo-cats) |
968 (error "Error in %s: No categories in list `todo-categories'" | 944 (error "Error in %s: No categories in list `todo-categories'" |
969 todo-file-do) | 945 todo-file-do) |
970 (goto-char (point-min)) | 946 (goto-char (point-min)) |
971 (and (search-forward "todo-cats:" nil t) | 947 (and (search-forward "todo-cats:" nil t) |
972 (replace-match "todo-categories:")) | 948 (replace-match "todo-categories:")) |
973 (make-local-variable 'todo-categories) | 949 (make-local-variable 'todo-categories) |
974 (setq todo-categories todo-cats))) | 950 (setq todo-categories todo-cats))) |
975 (beginning-of-line) | 951 (beginning-of-line) |
976 (todo-category-select)) | 952 (todo-category-select)) |
977 | 953 |
978 (defun todo-initial-setup () | 954 (defun todo-initial-setup () |
979 "Set up things to work properly in TODO mode." | 955 "Set up things to work properly in TODO mode." |
982 (todo-mode) | 958 (todo-mode) |
983 (todo-add-category "Todo")) | 959 (todo-add-category "Todo")) |
984 | 960 |
985 (provide 'todo-mode) | 961 (provide 'todo-mode) |
986 | 962 |
987 ;; --------------------------------------------------------------------------- | |
988 ;;; todo-mode.el ends here | 963 ;;; todo-mode.el ends here |
989 ;; --------------------------------------------------------------------------- |