diff options
| author | Stephen Berman | 2013-02-08 00:38:36 +0100 |
|---|---|---|
| committer | Stephen Berman | 2013-02-08 00:38:36 +0100 |
| commit | 0ad8680abcd1007c2306e32bf729346cfb15440e (patch) | |
| tree | 9b5b71c07b8404e01adcec8b011ce8749883a536 | |
| parent | 82a9ac454a9361edd0a1a6ce4aea9db16b51fc61 (diff) | |
| download | emacs-0ad8680abcd1007c2306e32bf729346cfb15440e.tar.gz emacs-0ad8680abcd1007c2306e32bf729346cfb15440e.zip | |
* calendar/todos.el: Bug fixes and improvements to item editing
and insertion.
(todos-check-format): Compare current value of todos-categories
with actual categories sexp.
(todos-repair-categories-sexp): Add warning to doc string about
category order getting restored to list element order.
(todos-mode-external-set): When todos-categories is nil, as in
Todos Edit mode, set it by reading actual categories sexp.
(todos-edit-mode): Make buffer writeable.
(todos-done-item-section-p): New function.
(todos-insert-item): Use it as part of preventing insertion here
in done items section. Move check for display of done items only
to just before setting new item's priority, and if cancelled after
toggling to todo items, restore display of done items.
(todos-edit-multiline-item): Don't base on todos-edit-multiline
but just narrow and change mode.
(todos-edit-multiline): Don't make indirect buffer but just widen
and change mode; also remove overlays.
(todos-edit-quit): Restore Todos mode and category display; when
quitting multiline item editing, ensure items above edited item
are visible in window if possible.
(todos-done-item-add-edit-or-delete-comment): If user moved point
during editing, make sure it moves back to edited item before
returning.
| -rw-r--r-- | lisp/ChangeLog | 27 | ||||
| -rw-r--r-- | lisp/calendar/todos.el | 193 |
2 files changed, 166 insertions, 54 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index ea640f11510..5c4f707d81f 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,30 @@ | |||
| 1 | 2013-02-07 Stephen Berman <stephen.berman@gmx.net> | ||
| 2 | |||
| 3 | * calendar/todos.el: Bug fixes and improvements to item editing | ||
| 4 | and insertion. | ||
| 5 | (todos-check-format): Compare current value of todos-categories | ||
| 6 | with actual categories sexp. | ||
| 7 | (todos-repair-categories-sexp): Add warning to doc string about | ||
| 8 | category order getting restored to list element order. | ||
| 9 | (todos-mode-external-set): When todos-categories is nil, as in | ||
| 10 | Todos Edit mode, set it by reading actual categories sexp. | ||
| 11 | (todos-edit-mode): Make buffer writeable. | ||
| 12 | (todos-done-item-section-p): New function. | ||
| 13 | (todos-insert-item): Use it as part of preventing insertion here | ||
| 14 | in done items section. Move check for display of done items only | ||
| 15 | to just before setting new item's priority, and if cancelled after | ||
| 16 | toggling to todo items, restore display of done items. | ||
| 17 | (todos-edit-multiline-item): Don't base on todos-edit-multiline | ||
| 18 | but just narrow and change mode. | ||
| 19 | (todos-edit-multiline): Don't make indirect buffer but just widen | ||
| 20 | and change mode; also remove overlays. | ||
| 21 | (todos-edit-quit): Restore Todos mode and category display; when | ||
| 22 | quitting multiline item editing, ensure items above edited item | ||
| 23 | are visible in window if possible. | ||
| 24 | (todos-done-item-add-edit-or-delete-comment): If user moved point | ||
| 25 | during editing, make sure it moves back to edited item before | ||
| 26 | returning. | ||
| 27 | |||
| 1 | 2013-02-05 Stephen Berman <stephen.berman@gmx.net> | 28 | 2013-02-05 Stephen Berman <stephen.berman@gmx.net> |
| 2 | 29 | ||
| 3 | * calendar/todos.el (todos-reset-done-separator-string): | 30 | * calendar/todos.el (todos-reset-done-separator-string): |
diff --git a/lisp/calendar/todos.el b/lisp/calendar/todos.el index 479d4c49377..ef05521937f 100644 --- a/lisp/calendar/todos.el +++ b/lisp/calendar/todos.el | |||
| @@ -1094,9 +1094,11 @@ where the invalid formatting was found." | |||
| 1094 | (save-restriction | 1094 | (save-restriction |
| 1095 | (widen) | 1095 | (widen) |
| 1096 | (goto-char (point-min)) | 1096 | (goto-char (point-min)) |
| 1097 | ;; Check for `todos-categories' sexp as the first line | 1097 | (let ((cats (prin1-to-string todos-categories)) |
| 1098 | (let ((cats (prin1-to-string todos-categories))) | 1098 | (sexp (buffer-substring-no-properties (line-beginning-position) |
| 1099 | (unless (looking-at (regexp-quote cats)) | 1099 | (line-end-position)))) |
| 1100 | ;; Check for `todos-categories' sexp as the first line | ||
| 1101 | (unless (string= sexp cats) | ||
| 1100 | (error "Invalid or missing todos-categories sexp"))) | 1102 | (error "Invalid or missing todos-categories sexp"))) |
| 1101 | (forward-line) | 1103 | (forward-line) |
| 1102 | (let ((legit (concat "\\(^" (regexp-quote todos-category-beg) "\\)" | 1104 | (let ((legit (concat "\\(^" (regexp-quote todos-category-beg) "\\)" |
| @@ -1400,7 +1402,11 @@ the file." | |||
| 1400 | (defun todos-repair-categories-sexp () | 1402 | (defun todos-repair-categories-sexp () |
| 1401 | "Repair corrupt Todos categories sexp. | 1403 | "Repair corrupt Todos categories sexp. |
| 1402 | This should only be needed as a consequence of careless manual | 1404 | This should only be needed as a consequence of careless manual |
| 1403 | editing or a bug in todos.el." | 1405 | editing or a bug in todos.el. |
| 1406 | |||
| 1407 | *Warning*: Calling this command restores the category order to | ||
| 1408 | the list element order in the Todos categories sexp, so any order | ||
| 1409 | changes made in Todos Categories mode will have to be made again." | ||
| 1404 | (interactive) | 1410 | (interactive) |
| 1405 | (let ((todos-categories (todos-make-categories-list t))) | 1411 | (let ((todos-categories (todos-make-categories-list t))) |
| 1406 | (todos-update-categories-sexp))) | 1412 | (todos-update-categories-sexp))) |
| @@ -1531,13 +1537,13 @@ The final element is \"*\", indicating an unspecified month.") | |||
| 1531 | (todos-item-start) | 1537 | (todos-item-start) |
| 1532 | (looking-at todos-done-string-start))) | 1538 | (looking-at todos-done-string-start))) |
| 1533 | 1539 | ||
| 1534 | ;; (defun todos-done-item-section-p () | 1540 | (defun todos-done-item-section-p () |
| 1535 | ;; "Return non-nil if point is in category's done items section." | 1541 | "Return non-nil if point is in category's done items section." |
| 1536 | ;; (save-excursion | 1542 | (save-excursion |
| 1537 | ;; (or (re-search-backward (concat "^" (regexp-quote todos-category-done)) | 1543 | (or (re-search-backward (concat "^" (regexp-quote todos-category-done)) |
| 1538 | ;; nil t) | 1544 | nil t) |
| 1539 | ;; (progn (goto-char (point-min)) | 1545 | (progn (goto-char (point-min)) |
| 1540 | ;; (looking-at todos-done-string-start))))) | 1546 | (looking-at todos-done-string-start))))) |
| 1541 | 1547 | ||
| 1542 | (defun todos-prefix-overlay () | 1548 | (defun todos-prefix-overlay () |
| 1543 | "Return this item's prefix overlay." | 1549 | "Return this item's prefix overlay." |
| @@ -2970,7 +2976,15 @@ which is the value of the user option | |||
| 2970 | ;; invocation of `todos-show', since there is then | 2976 | ;; invocation of `todos-show', since there is then |
| 2971 | ;; no buffer visiting the current file. | 2977 | ;; no buffer visiting the current file. |
| 2972 | (find-file-noselect todos-current-todos-file 'nowarn) | 2978 | (find-file-noselect todos-current-todos-file 'nowarn) |
| 2973 | todos-categories))) | 2979 | (or todos-categories |
| 2980 | ;; In Todos Edit mode todos-categories is now nil | ||
| 2981 | ;; since it uses same buffer as Todos mode but | ||
| 2982 | ;; doesn't have the latter's local variables. | ||
| 2983 | (save-excursion | ||
| 2984 | (goto-char (point-min)) | ||
| 2985 | (read (buffer-substring-no-properties | ||
| 2986 | (line-beginning-position) | ||
| 2987 | (line-end-position)))))))) | ||
| 2974 | (set (make-local-variable 'todos-categories) cats))) | 2988 | (set (make-local-variable 'todos-categories) cats))) |
| 2975 | 2989 | ||
| 2976 | (define-derived-mode todos-edit-mode text-mode "Todos-Ed" | 2990 | (define-derived-mode todos-edit-mode text-mode "Todos-Ed" |
| @@ -2978,7 +2992,8 @@ which is the value of the user option | |||
| 2978 | 2992 | ||
| 2979 | \\{todos-edit-mode-map}" | 2993 | \\{todos-edit-mode-map}" |
| 2980 | (todos-modes-set-1) | 2994 | (todos-modes-set-1) |
| 2981 | (todos-mode-external-set)) | 2995 | (todos-mode-external-set) |
| 2996 | (setq buffer-read-only nil)) | ||
| 2982 | 2997 | ||
| 2983 | (put 'todos-categories-mode 'mode-class 'special) | 2998 | (put 'todos-categories-mode 'mode-class 'special) |
| 2984 | 2999 | ||
| @@ -4602,19 +4617,14 @@ the priority is not given by HERE but by prompting." | |||
| 4602 | ;; file's first category. | 4617 | ;; file's first category. |
| 4603 | (set-buffer (find-buffer-visiting file))) | 4618 | (set-buffer (find-buffer-visiting file))) |
| 4604 | (setq todos-current-todos-file file) | 4619 | (setq todos-current-todos-file file) |
| 4605 | ;; If only done items are displayed in category, toggle to | ||
| 4606 | ;; todo items. | ||
| 4607 | (save-excursion | ||
| 4608 | (when (and (goto-char (point-min)) | ||
| 4609 | (looking-at todos-done-string-start)) | ||
| 4610 | (todos-show-done-only))) | ||
| 4611 | (unless todos-global-current-todos-file | 4620 | (unless todos-global-current-todos-file |
| 4612 | (setq todos-global-current-todos-file todos-current-todos-file)) | 4621 | (setq todos-global-current-todos-file todos-current-todos-file)) |
| 4613 | ;; These are not needed here, since they are called in | 4622 | ;; These are not needed here, since they are called in |
| 4614 | ;; todos-set-item-priority. | 4623 | ;; todos-set-item-priority. |
| 4615 | ;; (todos-category-number cat) | 4624 | ;; (todos-category-number cat) |
| 4616 | ;; (todos-category-select) | 4625 | ;; (todos-category-select) |
| 4617 | (let (buffer-read-only) | 4626 | (let ((buffer-read-only nil) |
| 4627 | done-only item-added) | ||
| 4618 | (setq new-item | 4628 | (setq new-item |
| 4619 | ;; Add date, time and diary marking as required. | 4629 | ;; Add date, time and diary marking as required. |
| 4620 | (concat (if (not (and diary (not todos-include-in-diary))) | 4630 | (concat (if (not (and diary (not todos-include-in-diary))) |
| @@ -4633,23 +4643,36 @@ the priority is not given by HERE but by prompting." | |||
| 4633 | (concat "\n" (make-string todos-indent-to-here 32)) | 4643 | (concat "\n" (make-string todos-indent-to-here 32)) |
| 4634 | new-item nil nil 1)) | 4644 | new-item nil nil 1)) |
| 4635 | (if here | 4645 | (if here |
| 4636 | (progn | 4646 | (if (or (todos-done-item-p) (todos-done-item-section-p)) |
| 4647 | (error "Cannot insert item in done items section") | ||
| 4637 | (unless (and todos-mm (equal cat ocat)) | 4648 | (unless (and todos-mm (equal cat ocat)) |
| 4638 | (todos-category-number cat) | 4649 | (todos-category-number cat) |
| 4639 | (todos-category-select) | 4650 | (todos-category-select) |
| 4640 | (goto-char (point-min))) | 4651 | (goto-char (point-min))) |
| 4641 | (todos-insert-with-overlays new-item)) | 4652 | (todos-insert-with-overlays new-item)) |
| 4642 | (unwind-protect | 4653 | (unwind-protect |
| 4643 | (todos-set-item-priority new-item cat t) | 4654 | (progn |
| 4644 | ;; In (at least) two circumstances, point may be at eob | 4655 | ;; If only done items are displayed in category, |
| 4645 | ;; and eob at window-start, so that that the todo items | 4656 | ;; toggle to todo items. |
| 4646 | ;; are out of view: (i) if item is inserted at end of | 4657 | (when (and (goto-char (point-min)) |
| 4647 | ;; category, (ii) if only done items are shown, this is | 4658 | (looking-at todos-done-string-start)) |
| 4648 | ;; (above) programmatically toggled to show todo items, | 4659 | (setq done-only t) |
| 4649 | ;; and user cancels before setting new item's | 4660 | (todos-show-done-only)) |
| 4650 | ;; priority. To make sure the todo items are displayed | 4661 | (todos-set-item-priority new-item cat t) |
| 4651 | ;; in the window, force recentering. | 4662 | (setq item-added t)) |
| 4652 | (recenter))) | 4663 | ;; If user cancels before setting priority, restore |
| 4664 | ;; display. | ||
| 4665 | (unless item-added | ||
| 4666 | (and done-only (todos-show-done-only))) | ||
| 4667 | ;; If todos section is not visible when insertion | ||
| 4668 | ;; command is called (either because only done items | ||
| 4669 | ;; were shown or because category was not in current | ||
| 4670 | ;; buffer), then if item is inserted at end of category, | ||
| 4671 | ;; point is at eob and eob at window-start, so that that | ||
| 4672 | ;; higher priority todo items are out of view. So we | ||
| 4673 | ;; recenter to make sure the todo items are displayed in | ||
| 4674 | ;; the window. | ||
| 4675 | (when item-added (recenter)))) | ||
| 4653 | (todos-update-count 'todo 1) | 4676 | (todos-update-count 'todo 1) |
| 4654 | (if (or diary todos-include-in-diary) (todos-update-count 'diary 1)) | 4677 | (if (or diary todos-include-in-diary) (todos-update-count 'diary 1)) |
| 4655 | (todos-update-categories-sexp)))))) | 4678 | (todos-update-categories-sexp)))))) |
| @@ -4790,29 +4813,77 @@ minibuffer; otherwise, edit it in Todos Edit mode." | |||
| 4790 | (todos-insert-with-overlays new) | 4813 | (todos-insert-with-overlays new) |
| 4791 | (move-to-column item-beg)))))) | 4814 | (move-to-column item-beg)))))) |
| 4792 | 4815 | ||
| 4816 | ;; (defun todos-edit-multiline-item () | ||
| 4817 | ;; "Edit current Todo item in Todos Edit mode. | ||
| 4818 | ;; Use of newlines invokes `todos-indent' to insure compliance with | ||
| 4819 | ;; the format of Diary entries." | ||
| 4820 | ;; (interactive) | ||
| 4821 | ;; (todos-edit-multiline t)) | ||
| 4822 | |||
| 4823 | ;; (defun todos-edit-multiline (&optional item) ;FIXME: not item editing command | ||
| 4824 | ;; "" ;FIXME | ||
| 4825 | ;; (interactive) | ||
| 4826 | ;; (let ((buffer-name todos-edit-buffer)) | ||
| 4827 | ;; (set-window-buffer | ||
| 4828 | ;; (selected-window) | ||
| 4829 | ;; (set-buffer (make-indirect-buffer | ||
| 4830 | ;; (file-name-nondirectory todos-current-todos-file) | ||
| 4831 | ;; buffer-name))) | ||
| 4832 | ;; (if item | ||
| 4833 | ;; (narrow-to-region (todos-item-start) (todos-item-end)) | ||
| 4834 | ;; (widen)) | ||
| 4835 | ;; (todos-edit-mode) | ||
| 4836 | ;; (message "%s" (substitute-command-keys | ||
| 4837 | ;; (concat "Type \\[todos-edit-quit] to check file format " | ||
| 4838 | ;; "validity and return to Todos mode.\n"))))) | ||
| 4839 | |||
| 4840 | ;; (defun todos-edit-quit () | ||
| 4841 | ;; "Return from Todos Edit mode to Todos mode. | ||
| 4842 | ;; If the item contains hard line breaks, make sure the following | ||
| 4843 | ;; lines are indented by `todos-indent-to-here' to conform to diary | ||
| 4844 | ;; format. | ||
| 4845 | |||
| 4846 | ;; If the whole file was in Todos Edit mode, check before returning | ||
| 4847 | ;; whether the file is still a valid Todos file and if so, also | ||
| 4848 | ;; recalculate the Todos categories sexp, in case changes were made | ||
| 4849 | ;; in the number or names of categories." | ||
| 4850 | ;; (interactive) | ||
| 4851 | ;; (if (eq (buffer-size) (- (point-max) (point-min))) | ||
| 4852 | ;; (when (todos-check-format) | ||
| 4853 | ;; (todos-repair-categories-sexp)) | ||
| 4854 | ;; ;; Ensure lines following hard newlines are indented. | ||
| 4855 | ;; (let ((item (replace-regexp-in-string | ||
| 4856 | ;; "\\(\n\\)[^[:blank:]]" | ||
| 4857 | ;; (concat "\n" (make-string todos-indent-to-here 32)) | ||
| 4858 | ;; (buffer-string) nil nil 1))) | ||
| 4859 | ;; (delete-region (point-min) (point-max)) | ||
| 4860 | ;; (insert item))) | ||
| 4861 | ;; (kill-buffer) | ||
| 4862 | ;; ;; In case next buffer is not the one holding todos-current-todos-file. | ||
| 4863 | ;; (todos-show)) | ||
| 4864 | |||
| 4793 | (defun todos-edit-multiline-item () | 4865 | (defun todos-edit-multiline-item () |
| 4794 | "Edit current Todo item in Todos Edit mode. | 4866 | "Edit current Todo item in Todos Edit mode. |
| 4795 | Use of newlines invokes `todos-indent' to insure compliance with | 4867 | Use of newlines invokes `todos-indent' to insure compliance with |
| 4796 | the format of Diary entries." | 4868 | the format of Diary entries." |
| 4797 | (interactive) | 4869 | (interactive) |
| 4798 | (todos-edit-multiline t)) | 4870 | (narrow-to-region (todos-item-start) (todos-item-end)) |
| 4799 | 4871 | (rename-buffer todos-edit-buffer) | |
| 4800 | (defun todos-edit-multiline (&optional item) | 4872 | (todos-edit-mode) |
| 4801 | "" | 4873 | (message "%s" (substitute-command-keys |
| 4874 | (concat "Type \\[todos-edit-quit] " | ||
| 4875 | "to return to Todos mode.\n")))) | ||
| 4876 | |||
| 4877 | (defun todos-edit-multiline (&optional item) ;FIXME: not item editing command | ||
| 4878 | "" ;FIXME | ||
| 4802 | (interactive) | 4879 | (interactive) |
| 4803 | (let ((buffer-name todos-edit-buffer)) | 4880 | (widen) |
| 4804 | (set-window-buffer | 4881 | (rename-buffer todos-edit-buffer) |
| 4805 | (selected-window) | 4882 | (todos-edit-mode) |
| 4806 | (set-buffer (make-indirect-buffer | 4883 | (remove-overlays) ; nil nil 'before-string) |
| 4807 | (file-name-nondirectory todos-current-todos-file) | 4884 | (message "%s" (substitute-command-keys |
| 4808 | buffer-name))) | 4885 | (concat "Type \\[todos-edit-quit] to check file format " |
| 4809 | (if item | 4886 | "validity and return to Todos mode.\n")))) |
| 4810 | (narrow-to-region (todos-item-start) (todos-item-end)) | ||
| 4811 | (widen)) | ||
| 4812 | (todos-edit-mode) | ||
| 4813 | (message "%s" (substitute-command-keys | ||
| 4814 | (concat "Type \\[todos-edit-quit] to check file format " | ||
| 4815 | "validity and return to Todos mode.\n"))))) | ||
| 4816 | 4887 | ||
| 4817 | (defun todos-edit-quit () | 4888 | (defun todos-edit-quit () |
| 4818 | "Return from Todos Edit mode to Todos mode. | 4889 | "Return from Todos Edit mode to Todos mode. |
| @@ -4827,17 +4898,28 @@ in the number or names of categories." | |||
| 4827 | (interactive) | 4898 | (interactive) |
| 4828 | (if (eq (buffer-size) (- (point-max) (point-min))) | 4899 | (if (eq (buffer-size) (- (point-max) (point-min))) |
| 4829 | (when (todos-check-format) | 4900 | (when (todos-check-format) |
| 4830 | (todos-repair-categories-sexp)) | 4901 | ;; FIXME: separate out sexp check? |
| 4902 | ;; If manual editing makes e.g. item counts change, have to | ||
| 4903 | ;; call this to update todos-categories, but it restores | ||
| 4904 | ;; category order to list order. | ||
| 4905 | ;; (todos-repair-categories-sexp) | ||
| 4906 | ;; Compare (todos-make-categories-list t) with sexp and if | ||
| 4907 | ;; different ask (todos-update-categories-sexp) ? | ||
| 4908 | (todos-mode) | ||
| 4909 | (todos-category-select)) | ||
| 4831 | ;; Ensure lines following hard newlines are indented. | 4910 | ;; Ensure lines following hard newlines are indented. |
| 4832 | (let ((item (replace-regexp-in-string | 4911 | (let ((beg (save-excursion (todos-item-start))) |
| 4912 | (item (replace-regexp-in-string | ||
| 4833 | "\\(\n\\)[^[:blank:]]" | 4913 | "\\(\n\\)[^[:blank:]]" |
| 4834 | (concat "\n" (make-string todos-indent-to-here 32)) | 4914 | (concat "\n" (make-string todos-indent-to-here 32)) |
| 4835 | (buffer-string) nil nil 1))) | 4915 | (buffer-string) nil nil 1))) |
| 4836 | (delete-region (point-min) (point-max)) | 4916 | (delete-region (point-min) (point-max)) |
| 4837 | (insert item))) | 4917 | (insert item) |
| 4838 | (kill-buffer) | 4918 | (todos-mode) |
| 4839 | ;; In case next buffer is not the one holding todos-current-todos-file. | 4919 | (todos-category-select) |
| 4840 | (todos-show)) | 4920 | (goto-char (point-min)) |
| 4921 | (goto-char beg) | ||
| 4922 | (recenter)))) | ||
| 4841 | 4923 | ||
| 4842 | (defun todos-edit-item-header-1 (what &optional inc) | 4924 | (defun todos-edit-item-header-1 (what &optional inc) |
| 4843 | "Function underlying commands to edit item date/time header. | 4925 | "Function underlying commands to edit item date/time header. |
| @@ -5565,6 +5647,7 @@ With prefix ARG delete an existing comment." | |||
| 5565 | (interactive "P") | 5647 | (interactive "P") |
| 5566 | (when (todos-done-item-p) | 5648 | (when (todos-done-item-p) |
| 5567 | (let ((item (todos-item-string)) | 5649 | (let ((item (todos-item-string)) |
| 5650 | (opoint (point)) | ||
| 5568 | (end (save-excursion (todos-item-end))) | 5651 | (end (save-excursion (todos-item-end))) |
| 5569 | comment buffer-read-only) | 5652 | comment buffer-read-only) |
| 5570 | (save-excursion | 5653 | (save-excursion |
| @@ -5579,6 +5662,8 @@ With prefix ARG delete an existing comment." | |||
| 5579 | (cons (match-string 1) 1))) | 5662 | (cons (match-string 1) 1))) |
| 5580 | (replace-match comment nil nil nil 1)) | 5663 | (replace-match comment nil nil nil 1)) |
| 5581 | (setq comment (read-string "Enter a comment: ")) | 5664 | (setq comment (read-string "Enter a comment: ")) |
| 5665 | ;; If user moved point during editing, make sure it moves back. | ||
| 5666 | (goto-char opoint) | ||
| 5582 | (todos-item-end) | 5667 | (todos-item-end) |
| 5583 | (insert " [" todos-comment-string ": " comment "]")))))) | 5668 | (insert " [" todos-comment-string ": " comment "]")))))) |
| 5584 | 5669 | ||