;; todo-mode.el -- Major mode for editing TODO list files
-;; Copyright (C) 1997, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1997, 1999, 2001 Free Software Foundation, Inc.
-;; Author: Oliver.Seidel@cl.cam.ac.uk
-;; Maintainer: FSF (unless Seidel can be found)
+;; Author: Oliver Seidel <os10000@seidel-space.de>
+;; [Not clear the above works, July 2000]
;; Created: 2 Aug 1997
-;; Version: $Id: todo-mode.el,v 1.39 2000/05/12 10:56:20 fx Exp $
-;; Keywords: Categorised TODO list editor, todo-mode
+;; Version: $Id: todo-mode.el,v 1.45 2001/07/05 13:44:53 gerd Exp $
+;; Keywords: calendar, todo
;; This file is part of GNU Emacs.
;; You may now enter new items by typing "M-x todo-insert-item",
;; or enter your TODO list file by typing "M-x todo-show".
;;
-;; -------------------------------------------------------------
-;;
-;; oh no, it doesn't work any more ... but Alex Schroeder
-;; <a.schroeder@bsiag.ch> writes:
-;;
-;; -------------------------------------------------------------
-;;
-;; 1. Call todo-show (I called todo-insert first)
-;; 2. Add some categories (I called todo-insert)
-;; 3. Save the buffer, restart Emacs (perhaps restarting Emacs is not
-;; required)
-;; 4. Only now can you start to add entries.
-;;
-;; This is a bit cumbersome, and it should be documented. You probably
-;;
-;; -------------------------------------------------------------
-;;
-;; and right he is. My apologies, I'll try to fix it sometime.
-;;
-;; -------------------------------------------------------------
-;;
;; The TODO list file has a special format and some auxiliary
;; information, which will be added by the todo-show function if
;; it attempts to visit an un-initialised file. Hence it is
;;
;; Which version of todo-mode.el does this documentation refer to?
;;
-;; $Id: todo-mode.el,v 1.39 2000/05/12 10:56:20 fx Exp $
+;; $Id: todo-mode.el,v 1.45 2001/07/05 13:44:53 gerd Exp $
+;;
+;; Pre-Requisites
+;;
+;; This package will require the following packages to be
+;; available on the load-path:
+;;
+;; time-stamp
+;; easymenu
;;
;; Operation
;;
;;
;; M-x todo-show will enter the todo list screen, here type
;;
-;; spc will toggle the display of sub-trees
-;;
;; + to go to next category
;; - to go to previous category
;; d to file the current entry, including a
;;; Code:
-(eval-when-compile
- (require 'outline)
- (require 'calendar)
- ;; Calendar dynamic bondage:
- (defvar date)
- (defvar entry))
-(autoload 'time-stamp-string "time-stamp")
-
;; User-configurable variables:
(defgroup todo nil
"Maintain a list of todo items."
+ :link '(emacs-commentary-link "todo-mode")
:version "21.1"
:group 'calendar)
-(defcustom todo-prefix "*/*"
+(defcustom todo-prefix "*/*"
"*TODO mode prefix for entries.
This is useful in conjunction with `calendar' and `diary' if you use
the diary file somewhat."
:type 'string
:group 'todo)
-(defcustom todo-file-do "~/.todo-do"
+(defcustom todo-file-do "~/.todo-do"
"*TODO mode list file."
:type 'file
:group 'todo)
-(defcustom todo-file-done "~/.todo-done"
+(defcustom todo-file-done "~/.todo-done"
"*TODO mode archive file."
:type 'file
:group 'todo)
window."
:type 'integer
:group 'todo)
-(defvar todo-edit-buffer " *TODO Edit*" "TODO Edit buffer name.")
+(defvar todo-edit-buffer " *TODO Edit*"
+ "TODO Edit buffer name.")
(defcustom todo-file-top "~/.todo-top"
"*TODO mode top priorities file.
;; My format string for the appt.el package is "%3b %2d, %y, %02I:%02M%p".
;;
(defcustom todo-time-string-format
- "%04y-%02m-%02d %02H:%02M"
+ "%:y-%02m-%02d %02H:%02M"
"*TODO mode time string format for done entries.
For details see the variable `time-stamp-format'."
:type 'string
:type 'string
:group 'todo)
+(autoload 'time-stamp-string "time-stamp")
+
(defun todo-entry-timestamp-initials ()
"Prepend timestamp and your initials to the head of a TODO entry."
(let ((time-stamp-format todo-time-string-format))
(concat (time-stamp-string) " " todo-initials ": ")))
+;; ---------------------------------------------------------------------------
+
;; Set up some helpful context ...
(defvar todo-categories nil
"TODO categories.")
+
(defvar todo-cats nil
"Old variable for holding the TODO categories.
Use `todo-categories' instead.")
-(defvar todo-previous-line 0
- "Previous line asked about.")
-(defvar todo-previous-answer 0
- "Previous answer got.")
-(defvar todo-category-number 0
- "TODO category number.")
-(defvar todo-category-sep (make-string 75 ?-)
- "Category separator.")
-(defvar todo-category-beg " --- "
- "Category start separator to be prepended onto category name.")
-(defvar todo-category-end "--- End"
- "Separator after a category.")
-(defvar todo-header "-*- mode: todo; "
- "Header of todo files.")
+(defvar todo-previous-line 0
+ "Previous line asked about.")
-;; ---------------------------------------------------------------------------
+(defvar todo-previous-answer 0
+ "Previous answer got.")
(defvar todo-mode-map
(let ((map (make-keymap)))
(suppress-keymap map t)
- (define-key map "?" 'todo-help)
- (define-key map " " 'todo-hide-show-subtree)
(define-key map "+" 'todo-forward-category)
(define-key map "-" 'todo-backward-category)
(define-key map "d" 'todo-file-item) ;done/delete
map)
"TODO mode keymap.")
-(defun todo-position (item list)
- "Return the position of the element in LIST testing `equal' to ITEM.
-Return nil if ITEM not found."
- (let ((pos 0)
- found)
- (while list
- (if (equal item (pop list))
- (setq list nil
- found pos)
- (setq pos (1+ pos))))
- found))
+(defvar todo-category-number 0 "TODO category number.")
+
+(defvar todo-tmp-buffer-name " *todo tmp*")
+
+(defvar todo-category-sep (make-string 75 ?-)
+ "Category separator.")
+
+(defvar todo-category-beg " --- "
+ "Category start separator to be prepended onto category name.")
+
+(defvar todo-category-end "--- End"
+ "Separator after a category.")
+
+(defvar todo-header "-*- mode: todo; "
+ "Header of todo files.")
+
+;; ---------------------------------------------------------------------------
(defun todo-category-select ()
"Make TODO mode display the current category correctly."
(let ((name (nth todo-category-number todo-categories)))
(setq mode-line-buffer-identification
+;; (concat "Category: " name))
(concat "Category: " (format "%18s" name)))
(widen)
(goto-char (point-min))
(goto-char (point-min)))))
(defalias 'todo-cat-slct 'todo-category-select)
-(defun todo-help () "Show TODO mode help."
- (interactive)
- (describe-function 'todo-mode))
-
-(defun todo-hide-show-subtree ()
- "Hide or Show subtrees in the TODO list."
- (interactive)
- (save-excursion
- (end-of-line)
- (if (outline-visible)
- (hide-subtree)
- (show-subtree))))
-
(defun todo-forward-category ()
"Go forward to TODO list of next category."
(interactive)
(message ""))
(defalias 'todo-cmd-next 'todo-forward-item)
-(defun todo-save () "Save the TODO list."
+(defun todo-save ()
+ "Save the TODO list."
(interactive)
(save-buffer)
(if todo-save-top-priorities-too (todo-save-top-priorities))
)
(defalias 'todo-cmd-save 'todo-save)
-(defun todo-quit () "Done with TODO list for now."
+(defun todo-quit ()
+ "Done with TODO list for now."
(interactive)
(widen)
(todo-save)
(bury-buffer))
(defalias 'todo-cmd-done 'todo-quit)
-(defun todo-edit-item () "Edit current TODO list entry."
+(defun todo-edit-item ()
+ "Edit current TODO list entry."
(interactive)
(let ((item (todo-item-string)))
(if (todo-string-multiline-p item)
(let ((buffer-name (generate-new-buffer-name todo-edit-buffer)))
(switch-to-buffer
(make-indirect-buffer
- (find-buffer-visiting todo-file-do) buffer-name))
+ (file-name-nondirectory todo-file-do) buffer-name))
(message "To exit, simply kill this buffer and return to list.")
(todo-edit-mode)
(narrow-to-region (todo-item-start) (todo-item-end))))
+;;;###autoload
(defun todo-add-category (cat)
"Add new category CAT to the TODO list."
(interactive "sCategory: ")
(save-window-excursion
- (add-to-list 'todo-categories cat)
+ (setq todo-categories (cons cat todo-categories))
(find-file todo-file-do)
(widen)
(goto-char (point-min))
(insert (format "%s%s%s\n%s\n%s %s\n"
todo-prefix todo-category-beg cat
todo-category-end
- todo-prefix todo-category-sep))
- (save-buffer))
+ todo-prefix todo-category-sep)))
0)
+;;;###autoload
(defun todo-add-item-non-interactively (new-item category)
"Insert NEW-ITEM in TODO list as a new entry in CATEGORY."
(save-excursion
(save-excursion
(if (string= "" category)
(setq category (nth todo-category-number todo-categories)))
- (setq todo-category-number
- (or (todo-position category todo-categories)
- (todo-add-category category)))
+ (let ((cat-exists (member category todo-categories)))
+ (setq todo-category-number
+ (if cat-exists
+ (- (length todo-categories) (length cat-exists))
+ (todo-add-category category))))
(todo-show)
(setq todo-previous-line 0)
(let ((top 1)
(forward-line (1- top)))
(insert new-item "\n")
(todo-backward-item)
- (progn ;;; horrible os10000 hack to make items appear when inserting into empty buffer
- (widen)
- (show-all)
- (todo-forward-category)
- (todo-backward-category))
(todo-save)
(message "")))
;;;###autoload
-(defun todo-insert-item (ARG)
+(defun todo-insert-item (arg)
"Insert new TODO list entry.
With a prefix argument solicit the category, otherwise use the current
category."
(history (cons 'categories (1+ todo-category-number)))
(current-category (nth todo-category-number todo-categories))
(category
- (if ARG
+ (if arg
current-category
- (completing-read
- (concat "Category ["
- current-category "]: ")
- (todo-category-alist) nil nil nil history))))
+ (completing-read (concat "Category [" current-category "]: ")
+ (todo-category-alist) nil nil nil
+ history current-category))))
(todo-add-item-non-interactively new-item category))))
(defalias 'todo-cmd-inst 'todo-insert-item)
todo-previous-answer)
(defalias 'todo-ask-p 'todo-more-important-p)
-(defun todo-delete-item () "Delete current TODO list entry."
+(defun todo-delete-item ()
+ "Delete current TODO list entry."
(interactive)
(if (> (count-lines (point-min) (point-max)) 0)
(let* ((todo-entry (todo-item-string-start))
(error "No TODO list entry to delete")))
(defalias 'todo-cmd-kill 'todo-delete-item)
-(defun todo-raise-item () "Raise priority of current entry."
+(defun todo-raise-item ()
+ "Raise priority of current entry."
(interactive)
(if (> (count-lines (point-min) (point)) 0)
(let ((item (todo-item-string)))
(insert item "\n"))
(message ""))
(error "No TODO list entry to raise")))
-(defalias 'todo-cmd-raise 'todo-raise-item)
+(defalias 'todo-cmd-rais 'todo-raise-item)
-(defun todo-lower-item () "Lower priority of current entry."
+(defun todo-lower-item ()
+ "Lower priority of current entry."
(interactive)
(if (> (count-lines (point) (point-max)) 1)
;; Assume there is a final newline
;; Utility functions:
+
+;;;###autoload
(defun todo-top-priorities (&optional nof-priorities category-pr-page)
"List top priorities for each category.
(or nof-priorities (setq nof-priorities todo-show-priorities))
(if (listp nof-priorities) ;universal argument
(setq nof-priorities (car nof-priorities)))
- (let ((todo-print-buffer-name " *todo-tmp*")
+ (let ((todo-print-buffer-name todo-tmp-buffer-name)
;;(todo-print-category-number 0)
(todo-category-break (if category-pr-page "\f" ""))
(cat-end
(copy-to-buffer todo-print-buffer-name (point-min) (point-max))
(set-buffer todo-print-buffer-name)
(goto-char (point-min))
- (if (re-search-forward (regexp-quote todo-header) nil t)
- (progn
- (beginning-of-line 1)
- (kill-line))) ;Remove mode line
+ (when (re-search-forward (regexp-quote todo-header) nil t)
+ (beginning-of-line 1)
+ (delete-region (point) (line-end-position)))
(while (re-search-forward ;Find category start
(regexp-quote (concat todo-prefix todo-category-beg))
nil t)
Number of entries for each category is given by NOF-PRIORITIES which
defaults to `todo-show-priorities'."
(interactive "P")
- (with-temp-buffer
- (todo-top-priorities nof-priorities)
- (write-file todo-file-top)))
+ (save-window-excursion
+ (save-excursion
+ (save-restriction
+ (todo-top-priorities nof-priorities)
+ (set-buffer todo-tmp-buffer-name)
+ (write-file todo-file-top)
+ (kill-this-buffer)))))
;;;###autoload
(defun todo-print (&optional category-pr-page)
"Print todo summary using `todo-print-function'.
-If CATEGORY-PR-PAGE is non-nil, a page separator \'^L\' is inserted
+If CATEGORY-PR-PAGE is non-nil, a page separator `^L' is inserted
between each category.
-Number of entries for each category is given by
-\'todo-print-priorities\'."
+Number of entries for each category is given by `todo-print-priorities'."
(interactive "P")
- (with-temp-buffer
- (todo-top-priorities todo-print-priorities
+ (save-window-excursion
+ (save-excursion
+ (save-restriction
+ (todo-top-priorities todo-print-priorities
category-pr-page)
- (funcall todo-print-function)
- (message "Todo printing done.")))
+ (set-buffer todo-tmp-buffer-name)
+ (and (funcall todo-print-function)
+ (kill-this-buffer))
+ (message "Todo printing done.")))))
(defun todo-jump-to-category ()
"Jump to a category. Default is previous category."
(interactive)
(let* ((categories todo-categories)
- (history (cons 'categories (1+ todo-category-number)))
+ (history (cons 'categories (1+ todo-category-number)))
+ (default (nth todo-category-number todo-categories))
(category (completing-read
- (concat "Category ["
- (nth todo-category-number todo-categories) "]: ")
- (todo-category-alist) nil nil nil history)))
+ (concat "Category [" default "]: ")
+ (todo-category-alist) nil nil nil history default)))
(if (string= "" category)
(setq category (nth todo-category-number todo-categories)))
(setq todo-category-number
- (or (todo-position category todo-categories)
- (todo-add-category category)))
+ (if (member category todo-categories)
+ (- (length todo-categories)
+ (length (member category todo-categories)))
+ (todo-add-category category)))
(todo-show)))
(defun todo-line-string ()
"Delete the current entry from the TODO list."
(delete-region (todo-item-start) (1+ (todo-item-end))))
-(defun todo-item-string () "Return current TODO list entry as a string."
+(defun todo-item-string ()
+ "Return current TODO list entry as a string."
(buffer-substring (todo-item-start) (todo-item-end)))
(defun todo-string-count-lines (string)
;; ---------------------------------------------------------------------------
-(easy-menu-define
- todo-menu todo-mode-map "Todo Menu"
- '("Todo"
- ["Next category" todo-forward-category t]
- ["Previous category" todo-backward-category t]
- ["Jump to category" todo-jump-to-category t]
- ["Show top priority items" todo-top-priorities t]
- ["Print categories" todo-print t]
- "---"
- ["Edit item" todo-edit-item t]
- ["File item" todo-file-item t]
- ["Insert new item" todo-insert-item t]
- ["Insert item here" todo-insert-item-here t]
- ["Kill item" todo-delete-item t]
- "---"
- ["Lower item priority" todo-lower-item t]
- ["Raise item priority" todo-raise-item t]
- "---"
- ["Next item" todo-forward-item t]
- ["Previous item" todo-backward-item t]
- "---"
- ["Save" todo-save t]
- ["Save Top Priorities" todo-save-top-priorities t]
- "---"
- ["Quit" todo-quit t]
- ))
+(easy-menu-define todo-menu todo-mode-map "Todo Menu"
+ '("Todo"
+ ["Next category" todo-forward-category t]
+ ["Previous category" todo-backward-category t]
+ ["Jump to category" todo-jump-to-category t]
+ ["Show top priority items" todo-top-priorities t]
+ ["Print categories" todo-print t]
+ "---"
+ ["Edit item" todo-edit-item t]
+ ["File item" todo-file-item t]
+ ["Insert new item" todo-insert-item t]
+ ["Insert item here" todo-insert-item-here t]
+ ["Kill item" todo-delete-item t]
+ "---"
+ ["Lower item priority" todo-lower-item t]
+ ["Raise item priority" todo-raise-item t]
+ "---"
+ ["Next item" todo-forward-item t]
+ ["Previous item" todo-backward-item t]
+ "---"
+ ["Save" todo-save t]
+ ["Save Top Priorities" todo-save-top-priorities t]
+ "---"
+ ["Quit" todo-quit t]
+ ))
;; As calendar reads .todo-do before todo-mode is loaded.
;;;###autoload
(setq mode-name "TODO")
(use-local-map todo-mode-map)
(easy-menu-add todo-menu)
- (setq fill-prefix "\t\t")
- (let ((prefix (regexp-quote todo-prefix)))
- (setq paragraph-separate prefix)
- (setq outline-regexp prefix))
- (outline-minor-mode 1)
- (goto-char (point-min))
- (outline-next-heading) ; get past -*- line
- (hide-other)
- (auto-fill-mode 1)
(run-hooks 'todo-mode-hook))
+(eval-when-compile
+ (defvar date)
+ (defvar entry))
+
;; Read about this function in the setup instructions above!
;;;###autoload
(defun todo-cp ()
(if (equal (calendar-current-date) date)
entry))
-(defun todo-edit-mode ()
+(define-derived-mode todo-edit-mode text-mode "TODO Edit"
"Major mode for editing items in the TODO list.
-\\{todo-edit-mode-map}"
- (text-mode)
- (setq major-mode 'todo-edit-mode)
- (setq mode-name "TODO Edit")
- (run-hooks 'todo-edit-mode-hook))
+\\{todo-edit-mode-map}")
;;;###autoload
(defun todo-show ()
(provide 'todo-mode)
-;; ---------------------------------------------------------------------------
;;; todo-mode.el ends here
-;; ---------------------------------------------------------------------------