diff options
| author | Stephen Berman | 2013-06-21 15:23:51 +0200 |
|---|---|---|
| committer | Stephen Berman | 2013-06-21 15:23:51 +0200 |
| commit | 03e6d46963d5fa9105f55416bf81cd6d1b57b8b5 (patch) | |
| tree | 788407de5698e21a52f97696db4abd58c15259bd | |
| parent | e2ff2f69b9db9bd96bc16dc02ed08cd053ef778c (diff) | |
| download | emacs-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/ChangeLog | 9 | ||||
| -rw-r--r-- | lisp/calendar/todo-mode.el | 257 |
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 @@ | |||
| 1 | 2013-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 | |||
| 1 | 2013-06-19 Stephen Berman <stephen.berman@gmx.net> | 10 | 2013-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 | ||
| 631 | When invoked in Todo mode, prompt for which todo file to visit. | 636 | When invoked in Todo mode, prompt for which todo file to visit. |
| 632 | When invoked outside of Todo mode with non-nil prefix argument | 637 | When invoked outside of Todo mode with non-nil prefix argument |
| 633 | SOLICIT-FILE prompt for which todo file to visit; otherwise visit | 638 | SOLICIT-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 |
| 635 | of Todo mode revisit this file or, with option | 640 | of 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 |
| 637 | file was last visited. | 642 | file was last visited. |
| 638 | 643 | ||
| 639 | Calling this command before any Todo file exists prompts for a | 644 | If you call this command before you have created any todo file in |
| 640 | file name and an initial category (defaulting to | 645 | the current format, and you have an todo file in old format, it |
| 641 | `todo-initial-file' and `todo-initial-category'), creates both | 646 | will ask you whether to convert that file and show it. |
| 642 | of these, visits the file and displays the category, and if | 647 | Otherwise, calling this command before any Todo file exists |
| 643 | option `todo-add-item-if-new-category' is non-nil (the default), | 648 | prompts for a file name and an initial category (defaulting to |
| 644 | prompts for the first item. | 649 | `todo-initial-file' and `todo-initial-category'), creates both of |
| 650 | these, visits the file and displays the category, and if option | ||
| 651 | `todo-add-item-if-new-category' is non-nil (the default), prompts | ||
| 652 | for the first item. | ||
| 645 | 653 | ||
| 646 | The first invocation of this command on an existing Todo file | 654 | The first invocation of this command on an existing Todo file |
| 647 | interacts with the option `todo-show-first': if its value is | 655 | interacts with the option `todo-show-first': if its value is |
| @@ -661,104 +669,116 @@ and done items are always shown on visiting a category. | |||
| 661 | Invoking this command in Todo Archive mode visits the | 669 | Invoking this command in Todo Archive mode visits the |
| 662 | corresponding Todo file, displaying the corresponding category." | 670 | corresponding 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 |