;;; todo-mode.el --- major mode for editing TODO list files
-;; Copyright (C) 1997, 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-;; 2008, 2009 Free Software Foundation, Inc.
+;; Copyright (C) 1997, 1999, 2001-2011 Free Software Foundation, Inc.
;; Author: Oliver Seidel <privat@os10000.net>
;; Maintainer: Stephen Berman <stephen.berman@gmx.net>
;; TODO is a major mode for EMACS which offers functionality to
;; treat most lines in one buffer as a list of items one has to
;; do. There are facilities to add new items, which are
-;; categorised, to edit or even delete items from the buffer.
+;; categorized, to edit or even delete items from the buffer.
;; The buffer contents are currently compatible with the diary,
;; so that the list of todo-items will show up in the FANCY diary
;; mode.
;;
;; Preface, Quickstart Installation
;;
-;; To get this to work, make emacs execute the line
+;; To get this to work, make Emacs execute the line
;;
;; (autoload 'todo-mode "todo-mode"
;; "Major mode for editing TODO lists." t)
;;
;; 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
+;; it attempts to visit an un-initialized file. Hence it is
;; recommended to use the todo-show function for the first time,
-;; in order to initialise the file, but it is not necessary
+;; in order to initialize the file, but it is not necessary
;; afterwards.
;;
;; As these commands are quite long to type, I would recommend
;; the addition of two bindings to your to your global keymap. I
-;; personally have the following in my initialisation file:
+;; personally have the following in my initialization file:
;;
;; (global-set-key "\C-ct" 'todo-show) ; switch to TODO buffer
;; (global-set-key "\C-ci" 'todo-insert-item) ; insert new item
;; o GNATS support
;; o elide multiline (as in bbdb, or, to a lesser degree, in
;; outline mode)
-;; o rewrite complete package to store data as lisp objects
+;; o rewrite complete package to store data as Lisp objects
;; and have display modes for display, for diary export,
;; etc. (Richard Stallman pointed out this is a bad idea)
;; o so base todo-mode.el on generic-mode.el instead
(defun todo-edit-item ()
"Edit current TODO list entry."
(interactive)
- (let ((item (todo-item-string)))
- (if (todo-string-multiline-p item)
- (todo-edit-multiline)
- (let ((new (read-from-minibuffer "Edit: " item)))
- (todo-remove-item)
- (insert new "\n")
- (todo-backward-item)
- (message "")))))
+ (if (< (point-min) (point-max))
+ (let ((item (todo-item-string)))
+ (if (todo-string-multiline-p item)
+ (todo-edit-multiline)
+ (let ((new (read-from-minibuffer "Edit: " item)))
+ (todo-remove-item)
+ (insert new "\n")
+ (todo-backward-item)
+ (message ""))))
+ (error "No TODO list entry to edit")))
(defalias 'todo-cmd-edit 'todo-edit-item)
(defun todo-edit-multiline ()
(unless (zerop (buffer-size buf))
(and (null todo-categories)
(null todo-cats)
- (error "Error in %s: File is non-empty but contains no category"
+ (error "Error in %s: File is non-empty but contains no category"
todo-file-do)))
(unless cat (setq cat (read-from-minibuffer prompt)))
(with-current-buffer buf
(setq todo-categories (cons cat todo-categories))
(widen)
(goto-char (point-min))
- (if (search-forward "-*- mode: todo; " 17 t)
+ (if (search-forward "-*- mode: todo; " (+ (point-min) 16) t)
(kill-line)
(insert "-*- mode: todo; \n")
(forward-char -1))
todo-prefix todo-category-beg cat
todo-category-end
todo-prefix todo-category-sep))
- (if (interactive-p)
+ (if (called-interactively-p 'interactive)
;; properly display the newly added category
(progn (setq todo-category-number 0) (todo-show))
0))))
;;;###autoload
(defun todo-insert-item (arg)
"Insert new TODO list entry.
-With a prefix argument solicit the category, otherwise use the current
+With a prefix argument ARG solicit the category, otherwise use the current
category."
(interactive "P")
(save-excursion
"New TODO entry: "
(if todo-entry-prefix-function
(funcall todo-entry-prefix-function))))))
- (unless (and (bolp) (eolp)) (goto-char (todo-item-start)))
+ (unless (and (bolp) (eolp)) (todo-item-start))
(insert (concat new-item "\n"))
(backward-char)
;; put point at start of new entry
- (goto-char (todo-item-start))))
+ (todo-item-start)))
(defun todo-more-important-p (line)
"Ask whether entry is more important than the one at LINE."
"(" comment ")"))
(goto-char (todo-item-end))
(insert " [" (nth todo-category-number todo-categories) "]")
- (goto-char (todo-item-start))
+ (todo-item-start)
(let ((temp-point (point)))
(if (looking-at (regexp-quote todo-prefix))
(replace-match (time-stamp-string))
;; Standard prefix -> timestamp
;; Else prefix non-standard item start with timestamp
(insert (time-stamp-string)))
- (append-to-file temp-point (1+ (todo-item-end)) todo-file-done)
- (delete-region temp-point (1+ (todo-item-end))))
+ (append-to-file temp-point (todo-item-end 'include-sep) todo-file-done)
+ (delete-region temp-point (todo-item-end 'include-sep)))
(todo-backward-item)
(message "")))
;;;###autoload
-(defun todo-top-priorities (&optional nof-priorities category-pr-page)
+(defun todo-top-priorities (&optional nof-priorities category-pr-page
+ interactive)
"List top priorities for each category.
Number of entries for each category is given by NOF-PRIORITIES which
-defaults to \'todo-show-priorities\'.
+defaults to `todo-show-priorities'.
If CATEGORY-PR-PAGE is non-nil, a page separator \'^L\' is inserted
-between each category."
+between each category.
+INTERACTIVE should be non-nil if this function is called interactively."
- (interactive "P")
+ (interactive "P\ni\nP")
(or nof-priorities (setq nof-priorities todo-show-priorities))
(if (listp nof-priorities) ;universal argument
(setq nof-priorities (car nof-priorities)))
(regexp-quote todo-prefix) " " todo-category-sep "\n")
(concat todo-category-end "\n"))))
beg end)
- (todo-show)
(save-excursion
+ (todo-show)
(save-restriction
- (widen)
- (copy-to-buffer todo-print-buffer-name (point-min) (point-max))
- (set-buffer todo-print-buffer-name)
- (goto-char (point-min))
- (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)
- (setq beg (+ (line-end-position) 1)) ;Start of first entry.
- (re-search-forward cat-end nil t)
- (setq end (match-beginning 0))
- (replace-match todo-category-break)
- (narrow-to-region beg end) ;In case we have too few entries.
- (goto-char (point-min))
- (if (zerop nof-priorities) ;Traverse entries.
- (goto-char end) ;All entries
- (todo-forward-item nof-priorities))
- (setq beg (point))
- (delete-region beg end)
- (widen))
- (and (looking-at "\f") (replace-match "")) ;Remove trailing form-feed.
- (goto-char (point-min)) ;Due to display buffer
- ))
- ;; Could have used switch-to-buffer as it has a norecord argument,
- ;; which is nice when we are called from e.g. todo-print.
- ;; Else we could have used pop-to-buffer.
- (display-buffer todo-print-buffer-name)
+ (save-current-buffer
+ (widen)
+ (copy-to-buffer todo-print-buffer-name (point-min) (point-max))
+ (set-buffer todo-print-buffer-name)
+ (goto-char (point-min))
+ (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)
+ (setq beg (+ (line-end-position) 1)) ;Start of first entry.
+ (re-search-forward cat-end nil t)
+ (setq end (match-beginning 0))
+ (replace-match todo-category-break)
+ (narrow-to-region beg end) ;In case we have too few entries.
+ (goto-char (point-min))
+ (if (zerop nof-priorities) ;Traverse entries.
+ (goto-char end) ;All entries
+ (todo-forward-item nof-priorities))
+ (setq beg (point))
+ (delete-region beg end)
+ (widen))
+ (and (looking-at "\f") (replace-match "")) ;Remove trailing form-feed.
+ (goto-char (point-min)) ;Due to display buffer
+ )))
+ (when interactive (display-buffer todo-print-buffer-name))
(message "Type C-x 1 to remove %s window. M-C-v to scroll the help."
todo-print-buffer-name)))
item))
(defun todo-item-start ()
- "Return point at start of current TODO list item."
- (save-excursion
- (beginning-of-line)
- (if (not (looking-at (regexp-quote todo-prefix)))
- (search-backward-regexp
- (concat "^" (regexp-quote todo-prefix)) nil t))
- (point)))
-
-(defun todo-item-end ()
- "Return point at end of current TODO list item."
+ "Go to start of current TODO list item and return point."
+ (beginning-of-line)
+ (if (not (looking-at (regexp-quote todo-prefix)))
+ (search-backward-regexp
+ (concat "^" (regexp-quote todo-prefix)) nil t))
+ (point))
+
+(defun todo-item-end (&optional include-sep)
+ "Return point at end of current TODO list item.
+If INCLUDE-SEP is non-nil, return point after the separator."
(save-excursion
(end-of-line)
- (search-forward-regexp
- (concat "^" (regexp-quote todo-prefix)) nil 'goto-end)
- (1- (line-beginning-position))))
+ (if (search-forward-regexp
+ (concat "^" (regexp-quote todo-prefix)) nil 'goto-end)
+ (goto-char (match-beginning 0)))
+ (unless include-sep (skip-chars-backward "\n"))
+ (point)))
(defun todo-remove-item ()
"Delete the current entry from the TODO list."
- (delete-region (todo-item-start) (1+ (todo-item-end))))
+ (delete-region (todo-item-start) (todo-item-end 'include-sep)))
(defun todo-item-string ()
"Return current TODO list entry as a string."
;; As calendar reads .todo-do before todo-mode is loaded.
;;;###autoload
-(defun todo-mode ()
- "Major mode for editing TODO lists.
-
-\\{todo-mode-map}"
- (interactive)
- (kill-all-local-variables)
- (setq major-mode 'todo-mode)
- (setq mode-name "TODO")
- (use-local-map todo-mode-map)
- (easy-menu-add todo-menu)
- (run-mode-hooks 'todo-mode-hook))
+(define-derived-mode todo-mode nil "TODO"
+ "Major mode for editing TODO lists."
+ (easy-menu-add todo-menu))
(defvar date)
(defvar entry)
(provide 'todo-mode)
-;; arch-tag: 6fd91be5-776e-4464-a109-da4ea0e4e497
;;; todo-mode.el ends here