aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Berman2013-06-21 15:23:51 +0200
committerStephen Berman2013-06-21 15:23:51 +0200
commit03e6d46963d5fa9105f55416bf81cd6d1b57b8b5 (patch)
tree788407de5698e21a52f97696db4abd58c15259bd
parente2ff2f69b9db9bd96bc16dc02ed08cd053ef778c (diff)
downloademacs-03e6d46963d5fa9105f55416bf81cd6d1b57b8b5.tar.gz
emacs-03e6d46963d5fa9105f55416bf81cd6d1b57b8b5.zip
* todo-mode.el: Offer to convert legacy file. Update commentary.
(todo-show): If a legacy file is found and no new todo file exists, offer to convert it and show it. Restore autoload cookie. (todo-convert-legacy-files): Delete unused local variable. If todo-directory doesn't exist, create it before writing to file. Check format of converted files. Prompt to show converted todo file.
-rw-r--r--lisp/calendar/ChangeLog9
-rw-r--r--lisp/calendar/todo-mode.el257
2 files changed, 153 insertions, 113 deletions
diff --git a/lisp/calendar/ChangeLog b/lisp/calendar/ChangeLog
index ec2b95f25f9..411a2fcae3f 100644
--- a/lisp/calendar/ChangeLog
+++ b/lisp/calendar/ChangeLog
@@ -1,3 +1,12 @@
12013-06-21 Stephen Berman <stephen.berman@gmx.net>
2
3 * todo-mode.el: Offer to convert legacy file. Update commentary.
4 (todo-show): If a legacy file is found and no new todo file
5 exists, offer to convert it and show it. Restore autoload cookie.
6 (todo-convert-legacy-files): Delete unused local variable.
7 If todo-directory doesn't exist, create it before writing to file.
8 Check format of converted files. Prompt to show converted todo file.
9
12013-06-19 Stephen Berman <stephen.berman@gmx.net> 102013-06-19 Stephen Berman <stephen.berman@gmx.net>
2 11
3 * todo-mode.el (todo-convert-legacy-files): Eliminate last change, 12 * todo-mode.el (todo-convert-legacy-files): Eliminate last change,
diff --git a/lisp/calendar/todo-mode.el b/lisp/calendar/todo-mode.el
index 8d4b8a9fab8..e3b92950797 100644
--- a/lisp/calendar/todo-mode.el
+++ b/lisp/calendar/todo-mode.el
@@ -64,9 +64,13 @@
64;; This package is a new version of Oliver Seidel's todo-mode.el. 64;; This package is a new version of Oliver Seidel's todo-mode.el.
65;; While it retains the same basic organization and handling of todo 65;; While it retains the same basic organization and handling of todo
66;; lists and the basic UI, it significantly extends these and adds 66;; lists and the basic UI, it significantly extends these and adds
67;; many features. This also required making changes to the internals, 67;; many features. This required also making changes to the internals,
68;; including the file format. To convert files in the old format to 68;; including the file format. If you have a todo file in old format,
69;; the new format, use the command `todo-convert-legacy-files'. 69;; then the first time you invoke `todo-show' (i.e., before you have
70;; created any todo file in the current format), it will ask you
71;; whether to convert that file and show it. If you choose not to
72;; convert the old-style file at this time, you can do so later by
73;; calling the command `todo-convert-legacy-files'.
70 74
71;;; Code: 75;;; Code:
72 76
@@ -556,7 +560,7 @@ less than or equal the category's top priority setting."
556 :group 'todo-faces) 560 :group 'todo-faces)
557 561
558;; ----------------------------------------------------------------------------- 562;; -----------------------------------------------------------------------------
559;;; Entering and exiting Todo 563;;; Entering and exiting
560;; ----------------------------------------------------------------------------- 564;; -----------------------------------------------------------------------------
561 565
562(defcustom todo-visit-files-commands (list 'find-file 'dired-find-file) 566(defcustom todo-visit-files-commands (list 'find-file 'dired-find-file)
@@ -625,23 +629,27 @@ Otherwise, `todo-show' always visits `todo-default-todo-file'."
625 :type 'boolean 629 :type 'boolean
626 :group 'todo) 630 :group 'todo)
627 631
632;;;###autoload
628(defun todo-show (&optional solicit-file) 633(defun todo-show (&optional solicit-file)
629 "Visit a Todo file and display one of its categories. 634 "Visit a todo file and display one of its categories.
630 635
631When invoked in Todo mode, prompt for which todo file to visit. 636When invoked in Todo mode, prompt for which todo file to visit.
632When invoked outside of Todo mode with non-nil prefix argument 637When invoked outside of Todo mode with non-nil prefix argument
633SOLICIT-FILE prompt for which todo file to visit; otherwise visit 638SOLICIT-FILE prompt for which todo file to visit; otherwise visit
634`todo-default-todo-file'. Subsequent invocations from outside 639`todo-default-todo-file'. Subsequent invocations from outside
635of Todo mode revisit this file or, with option 640of Todo mode revisit this file or, with option
636`todo-show-current-file' non-nil (the default), whichever Todo 641`todo-show-current-file' non-nil (the default), whichever todo
637file was last visited. 642file was last visited.
638 643
639Calling this command before any Todo file exists prompts for a 644If you call this command before you have created any todo file in
640file name and an initial category (defaulting to 645the current format, and you have an todo file in old format, it
641`todo-initial-file' and `todo-initial-category'), creates both 646will ask you whether to convert that file and show it.
642of these, visits the file and displays the category, and if 647Otherwise, calling this command before any Todo file exists
643option `todo-add-item-if-new-category' is non-nil (the default), 648prompts for a file name and an initial category (defaulting to
644prompts for the first item. 649`todo-initial-file' and `todo-initial-category'), creates both of
650these, visits the file and displays the category, and if option
651`todo-add-item-if-new-category' is non-nil (the default), prompts
652for the first item.
645 653
646The first invocation of this command on an existing Todo file 654The first invocation of this command on an existing Todo file
647interacts with the option `todo-show-first': if its value is 655interacts with the option `todo-show-first': if its value is
@@ -661,104 +669,116 @@ and done items are always shown on visiting a category.
661Invoking this command in Todo Archive mode visits the 669Invoking this command in Todo Archive mode visits the
662corresponding Todo file, displaying the corresponding category." 670corresponding Todo file, displaying the corresponding category."
663 (interactive "P") 671 (interactive "P")
664 (let* ((cat) 672 (catch 'shown
665 (show-first todo-show-first) 673 ;; If there is a legacy todo file but no todo file in the current
666 (file (cond ((or solicit-file 674 ;; format, offer to convert the legacy file and show it.
667 (and (called-interactively-p 'any)
668 (memq major-mode '(todo-mode
669 todo-archive-mode
670 todo-filtered-items-mode))))
671 (if (funcall todo-files-function)
672 (todo-read-file-name "Choose a Todo file to visit: "
673 nil t)
674 (user-error "There are no Todo files")))
675 ((and (eq major-mode 'todo-archive-mode)
676 ;; Called noninteractively via todo-quit
677 ;; to jump to corresponding category in
678 ;; todo file.
679 (not (called-interactively-p 'any)))
680 (setq cat (todo-current-category))
681 (concat (file-name-sans-extension
682 todo-current-todo-file) ".todo"))
683 (t
684 (or todo-current-todo-file
685 (and todo-show-current-file
686 todo-global-current-todo-file)
687 (todo-absolute-file-name todo-default-todo-file)
688 (todo-add-file)))))
689 add-item first-file)
690 (unless todo-default-todo-file 675 (unless todo-default-todo-file
691 ;; We just initialized the first todo file, so make it the default. 676 (let ((legacy-todo-file (if (boundp 'todo-file-do)
692 (setq todo-default-todo-file (todo-short-file-name file) 677 todo-file-do
693 first-file t) 678 (locate-user-emacs-file "todo-do" ".todo-do"))))
694 (todo-reevaluate-default-file-defcustom)) 679 (when (and (file-exists-p legacy-todo-file)
695 (unless (member file todo-visited) 680 (y-or-n-p (concat "Do you want to convert a copy of your "
696 ;; Can't setq t-c-t-f here, otherwise wrong file shown when 681 "old todo file to the new format? ")))
697 ;; todo-show is called from todo-show-categories-table. 682 (when (todo-convert-legacy-files)
698 (let ((todo-current-todo-file file)) 683 (throw 'shown nil)))))
699 (cond ((eq todo-show-first 'table) 684 (let* ((cat)
700 (todo-show-categories-table)) 685 (show-first todo-show-first)
701 ((memq todo-show-first '(top diary regexp)) 686 (file (cond ((or solicit-file
702 (let* ((shortf (todo-short-file-name file)) 687 (and (called-interactively-p 'any)
703 (fi-file (todo-absolute-file-name 688 (memq major-mode '(todo-mode
704 shortf todo-show-first))) 689 todo-archive-mode
705 (when (eq todo-show-first 'regexp) 690 todo-filtered-items-mode))))
706 (let ((rxfiles (directory-files todo-directory t 691 (if (funcall todo-files-function)
707 ".*\\.todr$" t))) 692 (todo-read-file-name "Choose a Todo file to visit: "
708 (when (and rxfiles (> (length rxfiles) 1)) 693 nil t)
709 (let ((rxf (mapcar 'todo-short-file-name rxfiles))) 694 (user-error "There are no Todo files")))
710 (setq fi-file (todo-absolute-file-name 695 ((and (eq major-mode 'todo-archive-mode)
711 (completing-read 696 ;; Called noninteractively via todo-quit
712 "Choose a regexp items file: " 697 ;; to jump to corresponding category in
713 rxf) 'regexp)))))) 698 ;; todo file.
714 (if (file-exists-p fi-file) 699 (not (called-interactively-p 'any)))
715 (set-window-buffer 700 (setq cat (todo-current-category))
716 (selected-window) 701 (concat (file-name-sans-extension
717 (set-buffer (find-file-noselect fi-file 'nowarn))) 702 todo-current-todo-file) ".todo"))
718 (message "There is no %s file for %s" 703 (t
719 (cond ((eq todo-show-first 'top) 704 (or todo-current-todo-file
720 "top priorities") 705 (and todo-show-current-file
721 ((eq todo-show-first 'diary) 706 todo-global-current-todo-file)
722 "diary items") 707 (todo-absolute-file-name todo-default-todo-file)
723 ((eq todo-show-first 'regexp) 708 (todo-add-file)))))
724 "regexp items")) 709 add-item first-file)
725 shortf) 710 (unless todo-default-todo-file
726 (setq todo-show-first 'first))))))) 711 ;; We just initialized the first todo file, so make it the default.
727 (when (or (member file todo-visited) 712 (setq todo-default-todo-file (todo-short-file-name file)
728 (eq todo-show-first 'first)) 713 first-file t)
729 (set-window-buffer (selected-window) 714 (todo-reevaluate-default-file-defcustom))
730 (set-buffer (find-file-noselect file 'nowarn))) 715 (unless (member file todo-visited)
731 ;; When quitting archive file, show corresponding category in 716 ;; Can't setq t-c-t-f here, otherwise wrong file shown when
732 ;; Todo file, if it exists. 717 ;; todo-show is called from todo-show-categories-table.
733 (when (assoc cat todo-categories) 718 (let ((todo-current-todo-file file))
734 (setq todo-category-number (todo-category-number cat))) 719 (cond ((eq todo-show-first 'table)
735 ;; If this is a new Todo file, add its first category. 720 (todo-show-categories-table))
736 (when (zerop (buffer-size)) 721 ((memq todo-show-first '(top diary regexp))
737 (let (cat-added) 722 (let* ((shortf (todo-short-file-name file))
738 (unwind-protect 723 (fi-file (todo-absolute-file-name
739 (setq todo-category-number 724 shortf todo-show-first)))
740 (todo-add-category todo-current-todo-file "") 725 (when (eq todo-show-first 'regexp)
741 add-item todo-add-item-if-new-category 726 (let ((rxfiles (directory-files todo-directory t
742 cat-added t) 727 ".*\\.todr$" t)))
743 (if cat-added 728 (when (and rxfiles (> (length rxfiles) 1))
744 ;; If the category was added, save the file now, so we 729 (let ((rxf (mapcar 'todo-short-file-name rxfiles)))
745 ;; don't risk having an empty todo file, which would 730 (setq fi-file (todo-absolute-file-name
746 ;; signal an error if we tried to visit it later, 731 (completing-read
747 ;; since doing that looks for category boundaries. 732 "Choose a regexp items file: "
748 (save-buffer 0) 733 rxf) 'regexp))))))
749 ;; If user cancels before adding the category, clean up 734 (if (file-exists-p fi-file)
750 ;; and exit, so we have a fresh slate the next time. 735 (set-window-buffer
751 (delete-file file) 736 (selected-window)
752 (setq todo-files (delete file todo-files)) 737 (set-buffer (find-file-noselect fi-file 'nowarn)))
753 (when first-file 738 (message "There is no %s file for %s"
754 (setq todo-default-todo-file nil 739 (cond ((eq todo-show-first 'top)
755 todo-current-todo-file nil)) 740 "top priorities")
756 (kill-buffer) 741 ((eq todo-show-first 'diary)
757 (keyboard-quit))))) 742 "diary items")
758 (save-excursion (todo-category-select)) 743 ((eq todo-show-first 'regexp)
759 (when add-item (todo-basic-insert-item))) 744 "regexp items"))
760 (setq todo-show-first show-first) 745 shortf)
761 (add-to-list 'todo-visited file))) 746 (setq todo-show-first 'first)))))))
747 (when (or (member file todo-visited)
748 (eq todo-show-first 'first))
749 (set-window-buffer (selected-window)
750 (set-buffer (find-file-noselect file 'nowarn)))
751 ;; When quitting archive file, show corresponding category in
752 ;; Todo file, if it exists.
753 (when (assoc cat todo-categories)
754 (setq todo-category-number (todo-category-number cat)))
755 ;; If this is a new Todo file, add its first category.
756 (when (zerop (buffer-size))
757 (let (cat-added)
758 (unwind-protect
759 (setq todo-category-number
760 (todo-add-category todo-current-todo-file "")
761 add-item todo-add-item-if-new-category
762 cat-added t)
763 (if cat-added
764 ;; If the category was added, save the file now, so we
765 ;; don't risk having an empty todo file, which would
766 ;; signal an error if we tried to visit it later,
767 ;; since doing that looks for category boundaries.
768 (save-buffer 0)
769 ;; If user cancels before adding the category, clean up
770 ;; and exit, so we have a fresh slate the next time.
771 (delete-file file)
772 (setq todo-files (delete file todo-files))
773 (when first-file
774 (setq todo-default-todo-file nil
775 todo-current-todo-file nil))
776 (kill-buffer)
777 (keyboard-quit)))))
778 (save-excursion (todo-category-select))
779 (when add-item (todo-basic-insert-item)))
780 (setq todo-show-first show-first)
781 (add-to-list 'todo-visited file))))
762 782
763(defun todo-save () 783(defun todo-save ()
764 "Save the current Todo file." 784 "Save the current Todo file."
@@ -4496,7 +4516,7 @@ name in `todo-directory'. See also the documentation string of
4496 (todo-initials-tem (and (boundp 'todo-initials) todo-initials)) 4516 (todo-initials-tem (and (boundp 'todo-initials) todo-initials))
4497 (todo-entry-prefix-function-tem (and (boundp 'todo-entry-prefix-function) 4517 (todo-entry-prefix-function-tem (and (boundp 'todo-entry-prefix-function)
4498 todo-entry-prefix-function)) 4518 todo-entry-prefix-function))
4499 todo-categories-tem todo-prefix-tem) 4519 todo-prefix-tem)
4500 ;; Convert `todo-file-do'. 4520 ;; Convert `todo-file-do'.
4501 (if (not (file-exists-p todo-file-do-tem)) 4521 (if (not (file-exists-p todo-file-do-tem))
4502 (message "No legacy Todo file exists") 4522 (message "No legacy Todo file exists")
@@ -4539,11 +4559,14 @@ name in `todo-directory'. See also the documentation string of
4539 (format "Save file as (default \"%s\"): " default) 4559 (format "Save file as (default \"%s\"): " default)
4540 nil nil default) 4560 nil nil default)
4541 ".todo")) 4561 ".todo"))
4562 (unless (file-exists-p todo-directory)
4563 (make-directory todo-directory))
4542 (write-region (point-min) (point-max) file nil 'nomessage nil t)) 4564 (write-region (point-min) (point-max) file nil 'nomessage nil t))
4543 (with-temp-buffer 4565 (with-temp-buffer
4544 (insert-file-contents file) 4566 (insert-file-contents file)
4545 (let ((todo-categories (todo-make-categories-list t))) 4567 (let ((todo-categories (todo-make-categories-list t)))
4546 (todo-update-categories-sexp)) 4568 (todo-update-categories-sexp)
4569 (todo-check-format))
4547 (write-region (point-min) (point-max) file nil 'nomessage)) 4570 (write-region (point-min) (point-max) file nil 'nomessage))
4548 (setq todo-files (funcall todo-files-function)) 4571 (setq todo-files (funcall todo-files-function))
4549 ;; Convert `todo-file-done'. 4572 ;; Convert `todo-file-done'.
@@ -4626,7 +4649,8 @@ name in `todo-directory'. See also the documentation string of
4626 (with-temp-buffer 4649 (with-temp-buffer
4627 (insert-file-contents file) 4650 (insert-file-contents file)
4628 (let* ((todo-categories (todo-make-categories-list t))) 4651 (let* ((todo-categories (todo-make-categories-list t)))
4629 (todo-update-categories-sexp)) 4652 (todo-update-categories-sexp)
4653 (todo-check-format))
4630 (write-region (point-min) (point-max) file nil 'nomessage) 4654 (write-region (point-min) (point-max) file nil 'nomessage)
4631 (setq archive-sexp (read (buffer-substring-no-properties 4655 (setq archive-sexp (read (buffer-substring-no-properties
4632 (line-beginning-position) 4656 (line-beginning-position)
@@ -4648,7 +4672,14 @@ name in `todo-directory'. See also the documentation string of
4648 (write-region (point-min) (point-max) file nil 'nomessage)) 4672 (write-region (point-min) (point-max) file nil 'nomessage))
4649 (setq todo-archives (funcall todo-files-function t))) 4673 (setq todo-archives (funcall todo-files-function t)))
4650 (todo-reevaluate-filelist-defcustoms) 4674 (todo-reevaluate-filelist-defcustoms)
4651 (message "Format conversion done."))))) 4675 (when (y-or-n-p (concat "Format conversion done; do you want to "
4676 "visit the converted file now? "))
4677 (setq todo-current-todo-file file)
4678 (unless todo-default-todo-file
4679 ;; We just initialized the first todo file, so make it the
4680 ;; default now to avoid an infinite recursion with todo-show.
4681 (setq todo-default-todo-file (todo-short-file-name file)))
4682 (todo-show))))))
4652 4683
4653;; ----------------------------------------------------------------------------- 4684;; -----------------------------------------------------------------------------
4654;;; Utility functions for Todo files, categories and items 4685;;; Utility functions for Todo files, categories and items