aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Berman2012-05-19 01:21:36 +0100
committerStephen Berman2012-05-19 01:21:36 +0100
commit520d912ec42980b1c543a87179e293e3dcbd2d55 (patch)
tree8c73747cbb1c970e4698d2fa2cb3fcf4e2d4cc30
parent0e89c3fc75c7de33bcb625c325600af227d2b1d1 (diff)
downloademacs-520d912ec42980b1c543a87179e293e3dcbd2d55.tar.gz
emacs-520d912ec42980b1c543a87179e293e3dcbd2d55.zip
* calendar/todos.el: Add and revise further doc strings and
comments. (todos-filter-function, todos-custom-items) (todos-custom-items-multifile): Remove. (todos-filter-done-items): New defcustom. (todos-item-end, todos-backward-item): Handle todos-filter-items-mode. (todos-filter-items): Check return value of caller first; tag archived items for todos-jump-to-item; delete categories sexp before processing filter; check todos-filter-done-items for whether to leave done items; remove custom filter; fix regexp for file and category tags; don't invoke buffer fontification. (powerset-recursive): Fix typo. (todos-key-bindings): Remove unused bindings. (todos-top-priorities-multifile, todos-diary-items-multifile) (todos-regexp-items-multifile): Use variable todos-multiple-files. (todos-jump-to-item): Fix regexp; handle archive tags; take todos-filter-done-items into account. (todos-insert-item-from-calendar): Relocate to end of file together with key-binding as addition to calendar.el.
-rw-r--r--lisp/ChangeLog24
-rw-r--r--lisp/calendar/todos.el379
2 files changed, 223 insertions, 180 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 1933b7cea01..1675c86684d 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,6 +1,28 @@
12012-09-21 Stephen Berman <stephen.berman@gmx.net>
2
3 * calendar/todos.el: Add and revise further doc strings and
4 comments.
5 (todos-filter-function, todos-custom-items)
6 (todos-custom-items-multifile): Remove.
7 (todos-filter-done-items): New defcustom.
8 (todos-item-end, todos-backward-item): Handle todos-filter-items-mode.
9 (todos-filter-items): Check return value of caller first; tag
10 archived items for todos-jump-to-item; delete categories sexp
11 before processing filter; check todos-filter-done-items for
12 whether to leave done items; remove custom filter; fix regexp for
13 file and category tags; don't invoke buffer fontification.
14 (powerset-recursive): Fix typo.
15 (todos-key-bindings): Remove unused bindings.
16 (todos-top-priorities-multifile, todos-diary-items-multifile)
17 (todos-regexp-items-multifile): Use variable todos-multiple-files.
18 (todos-jump-to-item): Fix regexp; handle archive tags; take
19 todos-filter-done-items into account.
20 (todos-insert-item-from-calendar): Relocate to end of file
21 together with key-binding as addition to calendar.el.
22
12012-09-20 Stephen Berman <stephen.berman@gmx.net> 232012-09-20 Stephen Berman <stephen.berman@gmx.net>
2 24
3 * calendar/todos.el Add and revise further doc strings and 25 * calendar/todos.el: Add and revise further doc strings and
4 comments; major code rearrangement. 26 comments; major code rearrangement.
5 (todos-merged-files, todos-prompt-merged-files) 27 (todos-merged-files, todos-prompt-merged-files)
6 (todos-print-priorities, todos-tmp-buffer-name) 28 (todos-print-priorities, todos-tmp-buffer-name)
diff --git a/lisp/calendar/todos.el b/lisp/calendar/todos.el
index b6b62808613..88a19b60a57 100644
--- a/lisp/calendar/todos.el
+++ b/lisp/calendar/todos.el
@@ -262,11 +262,12 @@ Todos category. The resulting control becomes the local value of
262 :group 'todos) 262 :group 'todos)
263 263
264(defun todos-special-buffer-name (buffer-type file-list) 264(defun todos-special-buffer-name (buffer-type file-list)
265 "Rename Todos special buffer. 265 "Rename Todos special buffer using BUFFER-TYPE and FILE-LIST.
266The new name is concatenated from the string BUFFER-TYPE and the 266
267names of the files in FILE-LIST. Used in the mode-list of 267The new name is constructed from the string BUFFER-TYPE, which
268buffers displaying top priorities, diary items, regexp items 268refers to one of the top priorities, diary or regexp item
269etc. for single and multiple files." 269filters, and the names of the filtered files in FILE-LIST. Used
270in Todos Filter Items mode."
270 (let* ((flist (if (listp file-list) file-list (list file-list))) 271 (let* ((flist (if (listp file-list) file-list (list file-list)))
271 (multi (> (length flist) 1)) 272 (multi (> (length flist) 1))
272 (fnames (mapconcat (lambda (f) (todos-short-file-name f)) 273 (fnames (mapconcat (lambda (f) (todos-short-file-name f))
@@ -275,27 +276,22 @@ etc. for single and multiple files."
275 " \"%s\"") buffer-type fnames)))) 276 " \"%s\"") buffer-type fnames))))
276 277
277(defcustom todos-filter-buffer "Todos filtered items" 278(defcustom todos-filter-buffer "Todos filtered items"
278 "Initial name of buffer in Todos Filter mode." 279 "Initial name of buffer in Todos Filter Items mode."
279 :type 'string 280 :type 'string
280 :group 'todos) 281 :group 'todos)
281 282
282(defcustom todos-top-priorities-buffer "Todos top priorities" 283(defcustom todos-top-priorities-buffer "Todos top priorities"
283 "Name of buffer displaying top priorities in Todos Filter mode." 284 "Buffer type string for `todos-special-buffer-name'."
284 :type 'string 285 :type 'string
285 :group 'todos) 286 :group 'todos)
286 287
287(defcustom todos-diary-items-buffer "Todos diary items" 288(defcustom todos-diary-items-buffer "Todos diary items"
288 "Name of buffer displaying diary items in Todos Filter mode." 289 "Buffer type string for `todos-special-buffer-name'."
289 :type 'string 290 :type 'string
290 :group 'todos) 291 :group 'todos)
291 292
292(defcustom todos-regexp-items-buffer "Todos regexp items" 293(defcustom todos-regexp-items-buffer "Todos regexp items"
293 "Name of buffer displaying regexp items in Todos Filter mode." 294 "Buffer type string for `todos-special-buffer-name'."
294 :type 'string
295 :group 'todos)
296
297(defcustom todos-custom-items-buffer "Todos custom items"
298 "Name of buffer displaying custom items in Todos Filter mode."
299 :type 'string 295 :type 'string
300 :group 'todos) 296 :group 'todos)
301 297
@@ -319,11 +315,6 @@ items in that category, which overrides NUM."
319 :type 'integer 315 :type 'integer
320 :group 'todos) 316 :group 'todos)
321 317
322(defcustom todos-filter-function nil
323 ""
324 :type 'function
325 :group 'todos)
326
327(defcustom todos-filter-files nil 318(defcustom todos-filter-files nil
328 "List of default files for multifile item filtering." 319 "List of default files for multifile item filtering."
329 :type `(set ,@(mapcar (lambda (f) (list 'const f)) 320 :type `(set ,@(mapcar (lambda (f) (list 'const f))
@@ -342,6 +333,12 @@ Called after adding or deleting a Todos file."
342 (funcall todos-files-function)))) 333 (funcall todos-files-function))))
343 :group 'todos))) 334 :group 'todos)))
344 335
336(defcustom todos-filter-done-items nil
337 "Non-nil to include done items when processing regexp filters.
338Done items from corresponding archive files are also included."
339 :type 'boolean
340 :group 'todos)
341
345(defcustom todos-ignore-archived-categories nil 342(defcustom todos-ignore-archived-categories nil
346 "Non-nil to ignore categories with only archived items. 343 "Non-nil to ignore categories with only archived items.
347When non-nil such categories are omitted from `todos-categories' 344When non-nil such categories are omitted from `todos-categories'
@@ -784,8 +781,6 @@ categories display according to priority."
784 781
785(defvar todos-font-lock-keywords 782(defvar todos-font-lock-keywords
786 (list 783 (list
787 ;; '(todos-nondiary-marker-matcher 1 todos-nondiary-face t)
788 ;; '(todos-nondiary-marker-matcher 2 todos-nondiary-face t)
789 '(todos-nondiary-marker-matcher 1 todos-done-sep-face t) 784 '(todos-nondiary-marker-matcher 1 todos-done-sep-face t)
790 '(todos-nondiary-marker-matcher 2 todos-done-sep-face t) 785 '(todos-nondiary-marker-matcher 2 todos-done-sep-face t)
791 ;; This is the face used by diary-lib.el. 786 ;; This is the face used by diary-lib.el.
@@ -1083,7 +1078,7 @@ number as its value."
1083 (overlay-put ov-sep 'display done-sep)))) 1078 (overlay-put ov-sep 'display done-sep))))
1084 (narrow-to-region (point-min) done-start) 1079 (narrow-to-region (point-min) done-start)
1085 ;; Loading this from todos-mode, or adding it to the mode hook, causes 1080 ;; Loading this from todos-mode, or adding it to the mode hook, causes
1086 ;; Emacs to hang in todos-item-start, at looking-at. 1081 ;; Emacs to hang in todos-item-start, at (looking-at todos-item-start).
1087 (when todos-highlight-item 1082 (when todos-highlight-item
1088 (require 'hl-line) 1083 (require 'hl-line)
1089 (hl-line-mode 1))))) 1084 (hl-line-mode 1)))))
@@ -1099,6 +1094,7 @@ If CATEGORY is nil, default to the current category."
1099 ((eq type 'archived) 3)))) 1094 ((eq type 'archived) 3))))
1100 (aref counts idx))) 1095 (aref counts idx)))
1101 1096
1097;; FIXME: rename to todos-increment-count
1102(defun todos-set-count (type increment &optional category) 1098(defun todos-set-count (type increment &optional category)
1103 "Increment count of TYPE items in CATEGORY by INCREMENT. 1099 "Increment count of TYPE items in CATEGORY by INCREMENT.
1104If CATEGORY is nil, default to the current category." 1100If CATEGORY is nil, default to the current category."
@@ -1255,7 +1251,9 @@ where the invalid formatting was found."
1255 t) 1251 t)
1256 1252
1257(defun todos-repair-categories-sexp () 1253(defun todos-repair-categories-sexp ()
1258 "Repair corrupt Todos categories sexp." 1254 "Repair corrupt Todos categories sexp.
1255This should only be needed as a consequence of careless manual
1256editing or a bug in todos.el."
1259 (interactive) 1257 (interactive)
1260 (let ((todos-categories-full (todos-make-categories-list t))) 1258 (let ((todos-categories-full (todos-make-categories-list t)))
1261 (todos-update-categories-sexp))) 1259 (todos-update-categories-sexp)))
@@ -1284,10 +1282,11 @@ where the invalid formatting was found."
1284 (unless (looking-at "^$") 1282 (unless (looking-at "^$")
1285 (let ((done (todos-done-item-p))) 1283 (let ((done (todos-done-item-p)))
1286 (todos-forward-item) 1284 (todos-forward-item)
1287 ;; Adjust if item is last unfinished one before displayed done items. 1285 (unless (eq major-mode 'todos-filter-items-mode)
1288 (when (and (not done) (todos-done-item-p)) 1286 ;; Adjust if item is last unfinished one before displayed done items.
1289 (forward-line -1)) 1287 (when (and (not done) (todos-done-item-p))
1290 (backward-char)) 1288 (forward-line -1))
1289 (backward-char)))
1291 (point))) 1290 (point)))
1292 1291
1293(defun todos-item-string () 1292(defun todos-item-string ()
@@ -1572,7 +1571,7 @@ Helper function for `todos-convert-legacy-files'."
1572;;; Item filtering 1571;;; Item filtering
1573 1572
1574(defvar todos-multiple-files nil 1573(defvar todos-multiple-files nil
1575 "List of files returned by `todos-multiple-files' widget.") 1574 "List of files selected from `todos-multiple-files' widget.")
1576 1575
1577(defvar todos-multiple-files-widget nil 1576(defvar todos-multiple-files-widget nil
1578 "Variable holding widget created by `todos-multiple-files'.") 1577 "Variable holding widget created by `todos-multiple-files'.")
@@ -1582,50 +1581,48 @@ Helper function for `todos-convert-legacy-files'."
1582 (require 'widget) 1581 (require 'widget)
1583 (eval-when-compile 1582 (eval-when-compile
1584 (require 'wid-edit)) 1583 (require 'wid-edit))
1585 (with-current-buffer (get-buffer-create "*Todos Filter Files*") 1584 (with-current-buffer (get-buffer-create "*Todos Filter Files*")
1586 (pop-to-buffer (current-buffer)) 1585 (pop-to-buffer (current-buffer))
1587 (erase-buffer) 1586 (erase-buffer)
1588 (kill-all-local-variables) 1587 (kill-all-local-variables)
1589 (widget-insert "Select files for generating the top priorities list.\n\n") 1588 (widget-insert "Select files for generating the top priorities list.\n\n")
1590 (setq todos-multiple-files-widget 1589 (setq todos-multiple-files-widget
1591 (widget-create 1590 (widget-create
1592 `(set ,@(mapcar (lambda (x) (list 'const x)) 1591 `(set ,@(mapcar (lambda (x) (list 'const x))
1593 (mapcar 'todos-short-file-name 1592 (mapcar 'todos-short-file-name
1594 (funcall todos-files-function)))))) 1593 (funcall todos-files-function))))))
1595 (widget-insert "\n") 1594 (widget-insert "\n")
1596 (widget-create 'push-button 1595 (widget-create 'push-button
1597 :notify (lambda (widget &rest ignore) 1596 :notify (lambda (widget &rest ignore)
1598 (setq todos-multiple-files 'quit) 1597 (setq todos-multiple-files 'quit)
1599 (quit-window t) 1598 (quit-window t)
1600 (exit-recursive-edit)) 1599 (exit-recursive-edit))
1601 "Cancel") 1600 "Cancel")
1602 (widget-insert " ") 1601 (widget-insert " ")
1603 (widget-create 'push-button 1602 (widget-create 'push-button
1604 :notify (lambda (&rest ignore) 1603 :notify (lambda (&rest ignore)
1605 (setq todos-multiple-files 1604 (setq todos-multiple-files
1606 (mapcar (lambda (f) 1605 (mapcar (lambda (f)
1607 (concat todos-files-directory 1606 (concat todos-files-directory
1608 f ".todo")) 1607 f ".todo"))
1609 (widget-value 1608 (widget-value
1610 todos-multiple-files-widget))) 1609 todos-multiple-files-widget)))
1611 (quit-window t) 1610 (quit-window t)
1612 (exit-recursive-edit)) 1611 (exit-recursive-edit))
1613 "Apply") 1612 "Apply")
1614 (use-local-map widget-keymap) 1613 (use-local-map widget-keymap)
1615 (widget-setup)) 1614 (widget-setup))
1616 (message "Click \"Apply\" after selecting files.") 1615 (message "Click \"Apply\" after selecting files.")
1617 (recursive-edit)) 1616 (recursive-edit))
1618 1617
1619;; FIXME: should done and archived items be included? Maybe just for regexp
1620;; and custom filters?
1621(defun todos-filter-items (filter &optional multifile) 1618(defun todos-filter-items (filter &optional multifile)
1622 "Build and display a list of items from different categories. 1619 "Build and display a list of items from different categories.
1623 1620
1624The items are selected according to the value of FILTER, which 1621The items are selected according to the value of FILTER, which
1625can be `top' for top priority items, `diary' for diary items, 1622can be `top' for top priority items, `diary' for diary items,
1626`regexp' for items matching a regular expresion entered by the 1623`regexp' for items matching a regular expresion entered by the
1627user, or `custom' for items chosen by user-defined function 1624user, or a cons cell of one of these symbols and a number set by
1628`todos-filter-function'. 1625the calling command, which overrides `todos-show-priorities'.
1629 1626
1630With non-nil argument MULTIFILE list top priorities of multiple 1627With non-nil argument MULTIFILE list top priorities of multiple
1631Todos files, by default those in `todos-filter-files'." 1628Todos files, by default those in `todos-filter-files'."
@@ -1634,9 +1631,11 @@ Todos files, by default those in `todos-filter-files'."
1634 (files (list todos-current-todos-file)) 1631 (files (list todos-current-todos-file))
1635 regexp fname bufstr cat beg end done) 1632 regexp fname bufstr cat beg end done)
1636 (when multifile 1633 (when multifile
1637 (setq files (if (or (consp filter) (null todos-filter-files)) 1634 (setq files (or todos-multiple-files ; Passed from todos-*-multifile.
1638 (progn (todos-multiple-files) todos-multiple-files) 1635 (if (or (consp filter)
1639 todos-filter-files) 1636 (null todos-filter-files))
1637 (progn (todos-multiple-files) todos-multiple-files)
1638 todos-filter-files))
1640 todos-multiple-files nil)) 1639 todos-multiple-files nil))
1641 (if (eq files 'quit) (keyboard-quit)) 1640 (if (eq files 'quit) (keyboard-quit))
1642 (if (null files) 1641 (if (null files)
@@ -1656,16 +1655,40 @@ Todos files, by default those in `todos-filter-files'."
1656 (with-current-buffer bf (save-buffer)))) 1655 (with-current-buffer bf (save-buffer))))
1657 (setq fname (todos-short-file-name f)) 1656 (setq fname (todos-short-file-name f))
1658 (with-temp-buffer 1657 (with-temp-buffer
1658 (when (and todos-filter-done-items (eq filter 'regexp))
1659 ;; If there is a corresponding archive file for the Todos file,
1660 ;; insert it first and add identifiers for todos-jump-to-item.
1661 (let ((arch (concat (file-name-sans-extension f) ".toda")))
1662 (when (file-exists-p arch)
1663 (insert-file-contents arch)
1664 ;; Delete Todos archive file categories sexp.
1665 (delete-region (line-beginning-position)
1666 (1+ (line-end-position)))
1667 (save-excursion
1668 (while (not (eobp))
1669 (when (re-search-forward
1670 (concat (if todos-filter-done-items
1671 (concat "\\(?:" todos-done-string-start
1672 "\\|" todos-date-string-start
1673 "\\)")
1674 todos-date-string-start)
1675 todos-date-pattern "\\(?: "
1676 diary-time-regexp "\\)?"
1677 (if todos-filter-done-items
1678 "\\]"
1679 (regexp-quote todos-nondiary-end)) "?")
1680 nil t)
1681 (insert "(archive) "))
1682 (forward-line))))))
1659 (insert-file-contents f) 1683 (insert-file-contents f)
1660 (goto-char (point-min)) 1684 ;; Delete Todos file categories sexp.
1685 (delete-region (line-beginning-position) (1+ (line-end-position)))
1661 (let (fnum) 1686 (let (fnum)
1662 ;; Unless the number of items to show was supplied by prefix 1687 ;; Unless the number of items to show was supplied by prefix
1663 ;; argument of caller, override `todos-show-priorities' with the 1688 ;; argument of caller, override `todos-show-priorities' with the
1664 ;; file-wide value from `todos-priorities-rules'. 1689 ;; file-wide value from `todos-priorities-rules'.
1665 (unless (consp filter) 1690 (unless (consp filter)
1666 (setq fnum (nth 1 (assoc f todos-priorities-rules)))) 1691 (setq fnum (nth 1 (assoc f todos-priorities-rules))))
1667 (unless (looking-at (concat "^" (regexp-quote todos-category-beg)))
1668 (kill-line 1))
1669 (while (re-search-forward 1692 (while (re-search-forward
1670 (concat "^" (regexp-quote todos-category-beg) "\\(.+\\)\n") 1693 (concat "^" (regexp-quote todos-category-beg) "\\(.+\\)\n")
1671 nil t) 1694 nil t)
@@ -1683,7 +1706,7 @@ Todos files, by default those in `todos-filter-files'."
1683 ;; FIXME: need this? 1706 ;; FIXME: need this?
1684 todos-show-priorities)))) 1707 todos-show-priorities))))
1685 (delete-region (match-beginning 0) (match-end 0)) 1708 (delete-region (match-beginning 0) (match-end 0))
1686 (setq beg (point)) ; Start of first item. 1709 (setq beg (point)) ; First item in the current category.
1687 (setq end (if (re-search-forward 1710 (setq end (if (re-search-forward
1688 (concat "^" (regexp-quote todos-category-beg)) 1711 (concat "^" (regexp-quote todos-category-beg))
1689 nil t) 1712 nil t)
@@ -1696,12 +1719,11 @@ Todos files, by default those in `todos-filter-files'."
1696 end t) 1719 end t)
1697 (match-beginning 0) 1720 (match-beginning 0)
1698 end)) 1721 end))
1699 ;; Leave done items only with regexp filter. 1722 (unless (and todos-filter-done-items (eq filter 'regexp))
1700 ;; FIXME: and custom filter? 1723 ;; Leave done items.
1701 (unless (eq filter 'regexp)
1702 (delete-region done end) 1724 (delete-region done end)
1703 (setq end done)) 1725 (setq end done))
1704 (narrow-to-region beg end) ; Process current category. 1726 (narrow-to-region beg end) ; Process only current category.
1705 (goto-char (point-min)) 1727 (goto-char (point-min))
1706 ;; Apply the filter. 1728 ;; Apply the filter.
1707 (cond ((eq filter 'diary) 1729 (cond ((eq filter 'diary)
@@ -1723,53 +1745,49 @@ Todos files, by default those in `todos-filter-files'."
1723 ;; there are no following done items, 1745 ;; there are no following done items,
1724 ;; todos-category-done string is left dangling, 1746 ;; todos-category-done string is left dangling,
1725 ;; because todos-forward-item jumps over it. 1747 ;; because todos-forward-item jumps over it.
1726 (if (and (eobp) (looking-back 1748 (if (and (eobp)
1727 (concat (regexp-quote todos-done-string) 1749 (looking-back
1728 "\n"))) 1750 (concat (regexp-quote todos-done-string)
1751 "\n")))
1729 (delete-region (point) (progn 1752 (delete-region (point) (progn
1730 (forward-line -2) 1753 (forward-line -2)
1731 (point)))))) 1754 (point))))))
1732 ((eq filter 'custom)
1733 (if todos-filter-function
1734 (funcall todos-filter-function)
1735 (error "No custom filter function has been defined")))
1736 (t ; Filter top priority items. 1755 (t ; Filter top priority items.
1737 (setq num (or cnum fnum num)) 1756 (setq num (or cnum fnum num))
1738 (unless (zerop num) 1757 (unless (zerop num)
1739 (todos-forward-item num)))) 1758 (todos-forward-item num))))
1740 (setq beg (point)) 1759 (setq beg (point))
1741 (unless (member filter '(diary regexp custom)) 1760 ;; Delete non-top-priority items.
1761 (unless (member filter '(diary regexp))
1742 (delete-region beg end)) 1762 (delete-region beg end))
1743 (goto-char (point-min)) 1763 (goto-char (point-min))
1744 ;; Add file (if using multiple files) and category tags to 1764 ;; Add file (if using multiple files) and category tags to
1745 ;; item. 1765 ;; item.
1746 (while (not (eobp)) 1766 (while (not (eobp))
1747 (when (re-search-forward 1767 (when (re-search-forward
1748 (concat "\\(" todos-done-string-start 1768 (concat (if todos-filter-done-items
1749 todos-date-pattern "\\( " diary-time-regexp 1769 (concat "\\(?:" todos-done-string-start
1750 "\\)?]\\)\\|\\(" 1770 "\\|" todos-date-string-start
1751 ;; todos-date-string-start doesn't work 1771 "\\)")
1752 ;; here because of `^' 1772 todos-date-string-start)
1753 "\\(" (regexp-quote todos-nondiary-start) 1773 todos-date-pattern "\\(?: " diary-time-regexp
1754 "\\|" (regexp-quote diary-nonmarking-symbol) 1774 "\\)?" (if todos-filter-done-items
1755 "\\)?" todos-date-pattern "\\( " 1775 "\\]"
1756 diary-time-regexp "\\)?" 1776 (regexp-quote todos-nondiary-end))
1757 (regexp-quote todos-nondiary-end) "?\\)") 1777 "?")
1758 nil t) 1778 nil t)
1759 (insert (concat " [" (if multifile (concat fname ":")) 1779 (insert " [")
1760 cat "]"))) 1780 (when (looking-at "(archive) ") (goto-char (match-end 0)))
1781 (insert (if multifile (concat fname ":") "") cat "]"))
1761 (forward-line)) 1782 (forward-line))
1762 (widen))) 1783 (widen)))
1763 (setq bufstr (buffer-string)) 1784 (setq bufstr (buffer-string))
1764 (with-current-buffer buf 1785 (with-current-buffer buf
1765 (let (buffer-read-only) 1786 (let (buffer-read-only)
1766 (insert bufstr))))))) 1787 (insert bufstr)))))))
1767 ;; FIXME: let-bind todos-mode-line-control according to FILTER?
1768 (set-window-buffer (selected-window) (set-buffer buf)) 1788 (set-window-buffer (selected-window) (set-buffer buf))
1769 (todos-prefix-overlays) 1789 (todos-prefix-overlays)
1770 (goto-char (point-min)) 1790 (goto-char (point-min)))))
1771 ;; FIXME: this is necessary -- why?
1772 (font-lock-fontify-buffer))))
1773 1791
1774(defun todos-set-top-priorities (&optional arg) 1792(defun todos-set-top-priorities (&optional arg)
1775 "Set number of top priorities shown by `todos-top-priorities'. 1793 "Set number of top priorities shown by `todos-top-priorities'.
@@ -2070,8 +2088,9 @@ which is the value of the user option
2070 (cond ((null l) 2088 (cond ((null l)
2071 (list nil)) 2089 (list nil))
2072 (t 2090 (t
2073 (let ((prev (todos-powerset (cdr l)))) 2091 (let ((prev (powerset-recursive (cdr l))))
2074 (append (mapcar (lambda (elt) (cons (car l) elt)) prev) 2092 (append (mapcar (lambda (elt) (cons (car l) elt))
2093 prev)
2075 prev))))) 2094 prev)))))
2076;; Elisp implementation of http://rosettacode.org/wiki/Power_set#C 2095;; Elisp implementation of http://rosettacode.org/wiki/Power_set#C
2077(defun powerset-bitwise (l) 2096(defun powerset-bitwise (l)
@@ -2244,8 +2263,6 @@ which is the value of the user option
2244 ("Fym" . todos-diary-items-multifile) 2263 ("Fym" . todos-diary-items-multifile)
2245 ("Fxx" . todos-regexp-items) 2264 ("Fxx" . todos-regexp-items)
2246 ("Fxm" . todos-regexp-items-multifile) 2265 ("Fxm" . todos-regexp-items-multifile)
2247 ("Fcc" . todos-custom-items)
2248 ("Fcm" . todos-custom-items-multifile)
2249 ;;("" . todos-save-top-priorities) 2266 ;;("" . todos-save-top-priorities)
2250 ;; navigation 2267 ;; navigation
2251 ("f" . todos-forward-category) 2268 ("f" . todos-forward-category)
@@ -2879,7 +2896,8 @@ list in each category."
2879 (cons 'top arg) 2896 (cons 'top arg)
2880 (setq files (if (or (consp arg) 2897 (setq files (if (or (consp arg)
2881 (null todos-filter-files)) 2898 (null todos-filter-files))
2882 (todos-multiple-files) 2899 (progn (todos-multiple-files)
2900 todos-multiple-files)
2883 todos-filter-files)) 2901 todos-filter-files))
2884 (if (equal arg '(16)) 2902 (if (equal arg '(16))
2885 (cons 'top (read-number 2903 (cons 'top (read-number
@@ -2903,7 +2921,8 @@ The files are those listed in `todos-filter-files'."
2903 (interactive "P") 2921 (interactive "P")
2904 (let ((buf todos-diary-items-buffer) 2922 (let ((buf todos-diary-items-buffer)
2905 (files (if (or arg (null todos-filter-files)) 2923 (files (if (or arg (null todos-filter-files))
2906 (todos-multiple-files) 2924 (progn (todos-multiple-files)
2925 todos-multiple-files)
2907 todos-filter-files))) 2926 todos-filter-files)))
2908 (todos-filter-items 'diary t) 2927 (todos-filter-items 'diary t)
2909 (todos-special-buffer-name buf files))) 2928 (todos-special-buffer-name buf files)))
@@ -2923,31 +2942,12 @@ The items are those in the files listed in `todos-filter-files'."
2923 (interactive "P") 2942 (interactive "P")
2924 (let ((buf todos-regexp-items-buffer) 2943 (let ((buf todos-regexp-items-buffer)
2925 (files (if (or arg (null todos-filter-files)) 2944 (files (if (or arg (null todos-filter-files))
2926 (todos-multiple-files) 2945 (progn (todos-multiple-files)
2946 todos-multiple-files)
2927 todos-filter-files))) 2947 todos-filter-files)))
2928 (todos-filter-items 'regexp t) 2948 (todos-filter-items 'regexp t)
2929 (todos-special-buffer-name buf files))) 2949 (todos-special-buffer-name buf files)))
2930 2950
2931(defun todos-custom-items ()
2932 "Display todo items filtered by `todos-filter-function'.
2933The items are those in the current Todos file."
2934 (interactive)
2935 (let ((buf todos-custom-items-buffer)
2936 (file todos-current-todos-file))
2937 (todos-filter-items 'custom)
2938 (todos-special-buffer-name buf file)))
2939
2940(defun todos-custom-items-multifile (&optional arg)
2941 "Display todo items filtered by `todos-filter-function'.
2942The items are those in the files listed in `todos-filter-files'."
2943 (interactive "P")
2944 (let ((buf todos-custom-items-buffer)
2945 (files (if (or arg (null todos-filter-files))
2946 (todos-multiple-files)
2947 todos-filter-files)))
2948 (todos-filter-items 'custom t)
2949 (todos-special-buffer-name buf files)))
2950
2951(defun todos-print (&optional to-file) 2951(defun todos-print (&optional to-file)
2952 "Produce a printable version of the current Todos buffer. 2952 "Produce a printable version of the current Todos buffer.
2953This converts overlays and soft line wrapping and, depending on 2953This converts overlays and soft line wrapping and, depending on
@@ -3183,7 +3183,8 @@ file, otherwise jump within the current Todos file."
3183 (interactive) 3183 (interactive)
3184 (let ((file (or (and other-file 3184 (let ((file (or (and other-file
3185 (todos-read-file-name "Choose a Todos file: " nil t)) 3185 (todos-read-file-name "Choose a Todos file: " nil t))
3186 ;; Jump to archived-only Categories from Todos Categories mode. 3186 ;; Jump to archived-only Categories from Todos Categories
3187 ;; mode.
3187 (and cat 3188 (and cat
3188 todos-ignore-archived-categories 3189 todos-ignore-archived-categories
3189 (zerop (todos-get-count 'todo cat)) 3190 (zerop (todos-get-count 'todo cat))
@@ -3192,25 +3193,26 @@ file, otherwise jump within the current Todos file."
3192 (concat (file-name-sans-extension 3193 (concat (file-name-sans-extension
3193 todos-current-todos-file) ".toda")) 3194 todos-current-todos-file) ".toda"))
3194 todos-current-todos-file 3195 todos-current-todos-file
3195 ;; If invoked from outside of Todos mode before todos-show... 3196 ;; If invoked from outside of Todos mode before
3197 ;; todos-show...
3196 todos-default-todos-file))) 3198 todos-default-todos-file)))
3197 (with-current-buffer (find-file-noselect file) 3199 (with-current-buffer (find-file-noselect file)
3198 (and other-file (setq todos-current-todos-file file)) 3200 (and other-file (setq todos-current-todos-file file))
3199 (let ((category (or (and (assoc cat todos-categories) cat) 3201 (let ((category (or (and (assoc cat todos-categories) cat)
3200 (todos-read-category "Jump to category: ")))) 3202 (todos-read-category "Jump to category: "))))
3201 ;; Clean up after selecting category in Todos Categories mode. 3203 ;; Clean up after selecting category in Todos Categories mode.
3202 (if (string= (buffer-name) todos-categories-buffer) 3204 (if (string= (buffer-name) todos-categories-buffer)
3203 (kill-buffer)) 3205 (kill-buffer))
3204 (if (or cat other-file) 3206 (if (or cat other-file)
3205 (set-window-buffer (selected-window) 3207 (set-window-buffer (selected-window)
3206 (set-buffer (get-file-buffer file)))) 3208 (set-buffer (get-file-buffer file))))
3207 (unless todos-global-current-todos-file 3209 (unless todos-global-current-todos-file
3208 (setq todos-global-current-todos-file todos-current-todos-file)) 3210 (setq todos-global-current-todos-file todos-current-todos-file))
3209 (todos-category-number category) 3211 (todos-category-number category)
3210 (if (> todos-category-number (length todos-categories)) 3212 (if (> todos-category-number (length todos-categories))
3211 (setq todos-category-number (todos-add-category category))) 3213 (setq todos-category-number (todos-add-category category)))
3212 (todos-category-select) 3214 (todos-category-select)
3213 (goto-char (point-min)))))) 3215 (goto-char (point-min))))))
3214 3216
3215(defun todos-jump-to-category-other-file () 3217(defun todos-jump-to-category-other-file ()
3216 "Jump to a category in another Todos file. 3218 "Jump to a category in another Todos file.
@@ -3223,17 +3225,28 @@ The category is chosen by prompt, with TAB completion."
3223 (interactive) 3225 (interactive)
3224 (let ((str (todos-item-string)) 3226 (let ((str (todos-item-string))
3225 (buf (current-buffer)) 3227 (buf (current-buffer))
3226 cat file beg) 3228 cat file archive beg)
3227 (string-match (concat todos-date-string-start todos-date-pattern 3229 (string-match (concat (if todos-filter-done-items
3228 "\\(?: " diary-time-regexp "\\)?" 3230 (concat "\\(?:" todos-done-string-start "\\|"
3229 (regexp-quote todos-nondiary-end) "?" 3231 todos-date-string-start "\\)")
3230 "\\(?3: \\[\\(?2:.*:\\)?\\(?1:.*\\)\\]\\).*$") str) 3232 todos-date-string-start)
3233 todos-date-pattern "\\(?: " diary-time-regexp "\\)?"
3234 (if todos-filter-done-items
3235 "\\]"
3236 (regexp-quote todos-nondiary-end)) "?"
3237 "\\(?4: \\[\\(?3:(archive) \\)?\\(?2:.*:\\)?"
3238 "\\(?1:.*\\)\\]\\).*$") str)
3231 (setq cat (match-string 1 str)) 3239 (setq cat (match-string 1 str))
3232 (setq file (match-string 2 str)) 3240 (setq file (match-string 2 str))
3233 (setq str (replace-match "" nil nil str 3)) 3241 (setq archive (string= (match-string 3 str) "(archive) "))
3242 (setq str (replace-match "" nil nil str 4))
3234 (setq file (if file 3243 (setq file (if file
3235 (concat todos-files-directory (substring file 0 -1) ".todo") 3244 (concat todos-files-directory (substring file 0 -1)
3236 todos-global-current-todos-file)) 3245 (if archive ".toda" ".todo"))
3246 (if archive
3247 (concat (file-name-sans-extension
3248 todos-global-current-todos-file) ".toda")
3249 todos-global-current-todos-file)))
3237 (find-file-noselect file) 3250 (find-file-noselect file)
3238 (with-current-buffer (get-file-buffer file) 3251 (with-current-buffer (get-file-buffer file)
3239 (widen) 3252 (widen)
@@ -3246,7 +3259,9 @@ The category is chosen by prompt, with TAB completion."
3246 (set-window-buffer (selected-window) (set-buffer (get-file-buffer file))) 3259 (set-window-buffer (selected-window) (set-buffer (get-file-buffer file)))
3247 (setq todos-current-todos-file file) 3260 (setq todos-current-todos-file file)
3248 (setq todos-category-number (todos-category-number cat)) 3261 (setq todos-category-number (todos-category-number cat))
3249 (todos-category-select) 3262 (let ((todos-show-with-done (if todos-filter-done-items t
3263 todos-show-with-done)))
3264 (todos-category-select))
3250 (goto-char beg))) 3265 (goto-char beg)))
3251 3266
3252;; FIXME ? disallow prefix arg value < 1 (re-search-* allows these) 3267;; FIXME ? disallow prefix arg value < 1 (re-search-* allows these)
@@ -3277,14 +3292,15 @@ With numerical prefix COUNT, move point COUNT items upward,"
3277 (todos-item-start) 3292 (todos-item-start)
3278 (unless (bobp) 3293 (unless (bobp)
3279 (re-search-backward todos-item-start nil t (or count 1))) 3294 (re-search-backward todos-item-start nil t (or count 1)))
3280 ;; If points advances by one from a done to a todo item, go back to the 3295 (unless (eq major-mode 'todos-filter-items-mode)
3281 ;; space above todos-done-separator, since that is a legitimate place to 3296 ;; If points advances by one from a done to a todo item, go back to the
3282 ;; insert an item. But skip this space if count > 1, since that should 3297 ;; space above todos-done-separator, since that is a legitimate place to
3283 ;; only stop on an item (FIXME: or not?) 3298 ;; insert an item. But skip this space if count > 1, since that should
3284 (when (and done (not (todos-done-item-p)) 3299 ;; only stop on an item (FIXME: or not?)
3285 (or (not count) (= count 1))) 3300 (when (and done (not (todos-done-item-p))
3286 (re-search-forward (concat "^" (regexp-quote todos-category-done)) nil t) 3301 (or (not count) (= count 1)))
3287 (forward-line -1)))) 3302 (re-search-forward (concat "^" (regexp-quote todos-category-done)) nil t)
3303 (forward-line -1)))))
3288 3304
3289;; FIXME: (i) Extend search to other Todos files. (ii) Allow navigating among 3305;; FIXME: (i) Extend search to other Todos files. (ii) Allow navigating among
3290;; hits. 3306;; hits.
@@ -3906,30 +3922,14 @@ same except the priority is not given by HERE but by prompting."
3906 ;; *Calendar* is now current buffer. 3922 ;; *Calendar* is now current buffer.
3907 (local-set-key (kbd "RET") 'exit-recursive-edit) 3923 (local-set-key (kbd "RET") 'exit-recursive-edit)
3908 (message "Put cursor on a date and type <return> to set it.") 3924 (message "Put cursor on a date and type <return> to set it.")
3909 ;; FIXME: is there a better way than recursive-edit? 3925 ;; FIXME: is there a better way than recursive-edit? Use unwind-protect?
3910 ;; FIXME: use unwind-protect? Check recursive-depth? 3926 ;; Check recursive-depth?
3911 (recursive-edit) 3927 (recursive-edit)
3912 (setq todos-date-from-calendar 3928 (setq todos-date-from-calendar
3913 (calendar-date-string (calendar-cursor-to-date t) t t)) 3929 (calendar-date-string (calendar-cursor-to-date t) t t))
3914 (calendar-exit) 3930 (calendar-exit)
3915 todos-date-from-calendar)) 3931 todos-date-from-calendar))
3916 3932
3917;; FIXME: autoload when key-binding is defined in calendar.el
3918(defun todos-insert-item-from-calendar ()
3919 ""
3920 (interactive)
3921 ;; FIXME: todos-current-todos-file is nil here, better to solicit Todos file?
3922 ;; FIXME: t-g-c-t-f is nil if no Todos file has been visited
3923 (pop-to-buffer (file-name-nondirectory todos-global-current-todos-file))
3924 (todos-show)
3925 ;; FIXME: this now calls todos-set-date-from-calendar
3926 (todos-insert-item t 'calendar))
3927
3928;; FIXME: calendar is loaded before todos
3929;; (add-hook 'calendar-load-hook
3930 ;; (lambda ()
3931 (define-key calendar-mode-map "it" 'todos-insert-item-from-calendar);))
3932
3933(defun todos-delete-item () 3933(defun todos-delete-item ()
3934 "Delete at least one item in this category. 3934 "Delete at least one item in this category.
3935 3935
@@ -4828,6 +4828,27 @@ archive, the archive file is deleted."
4828 4828
4829;;; todos.el ends here 4829;;; todos.el ends here
4830 4830
4831
4832;; ---------------------------------------------------------------------------
4833;;; Addition to calendar.el
4834
4835;; FIXME: autoload when key-binding is defined in calendar.el
4836(defun todos-insert-item-from-calendar ()
4837 ""
4838 (interactive)
4839 ;; FIXME: todos-current-todos-file is nil here, better to solicit Todos
4840 ;; file? todos-global-current-todos-file is nil if no Todos file has been
4841 ;; visited
4842 (pop-to-buffer (file-name-nondirectory todos-global-current-todos-file))
4843 (todos-show)
4844 ;; FIXME: this now calls todos-set-date-from-calendar
4845 (todos-insert-item t 'calendar))
4846
4847;; FIXME: calendar is loaded before todos
4848;; (add-hook 'calendar-load-hook
4849 ;; (lambda ()
4850(define-key calendar-mode-map "it" 'todos-insert-item-from-calendar);))
4851
4831;; --------------------------------------------------------------------------- 4852;; ---------------------------------------------------------------------------
4832;;; necessitated adaptations to diary-lib.el 4853;;; necessitated adaptations to diary-lib.el
4833 4854