0

I have a list of repeatable tasks. Sometimes I deactivate them by changing state to CANCELED. But when I do it the new SCHEDULE is created in the future. To prevent that from happening I change timestamp to inactive by hand, and when I want to bring this repeatable task back to TODO I have to remember to activate timestamp.

I could remove timestamp from task before canceling it, and set it again if necessary, but I want to keep it as inactive in case I would like to return to it in the future, so I know repeatable setting from the past.

How could I make task timestamp (DEADLINE and/or SCHEDULED) inactive while switching to CANCELED state, and active while changing it to TODO automatically?

EDIT: I managed to put together something like this, but it doesn't work.

(defun jarfar/org-state-canceled-timestamp-toggle ()
  "Toggle active/inactive SCHEDULED or DEADLINE timestamp when switching between CANCELED and TODO state."
  (save-excursion
    (let ((state (org-get-todo-state)))
      (cond
        ((equal state "CANCELED")
          (when (and
                  (org-get-deadline-time (point))
                  (search-forward-regexp "DEADLINE: .*" nil t)
                  (null (deactivate-mark))
                  (equal (char-to-string (char-after)) ">"))
            (org-toggle-timestamp-type))
          (when (and
                  (org-get-scheduled-time (point))
                  (search-forward-regexp "SCHEDULED: .*" nil t)
                  (null (deactivate-mark))
                  (equal (char-to-string (char-after)) ">"))
            (org-toggle-timestamp-type)))
        ((equal state "TODO")
          (when (and
                  (org-get-deadline-time (point))
                  (search-forward-regexp "DEADLINE: .*" nil t)
                  (null (deactivate-mark))
                  (equal (char-to-string (char-after)) "]"))
            (org-toggle-timestamp-type))
          (when (and
                  (org-get-scheduled-time (point))
                  (search-forward-regexp "SCHEDULED: .*" nil t)
                  (null (deactivate-mark))
                  (equal (char-to-string (char-after)) "]"))
            (org-toggle-timestamp-type)))))
    (when (equal (buffer-name (current-buffer)) "*Org Agenda*")
      (with-current-buffer "*Org Agenda*" (org-agenda-redo)))))

(add-hook 'org-after-todo-state-change-hook 'jarfar/org-state-canceled-timestamp-toggle)

3
  • Use org-after-todo-state-change-hook.
    – NickD
    Jul 28, 2020 at 12:29
  • @NickD, yes but what put inside the function?
    – Navidot
    Jul 28, 2020 at 23:20
  • Yes, I think there is some strange behavior that I had forgotten about, having to do with recurring DEADLINEs. I have to do some digging.
    – NickD
    Jul 29, 2020 at 1:22

1 Answer 1

0

I figured this out. My solution is below.

The problem was with org-at-timestamp-p function which takes only one parameter, so we can't tell that the timestamp is valid agenda like timestamp and it's inactive at the same time. So to change inactive timestamp to active I had to detect inactive state by checking the character at point if it match closing bracket. The good part is that search-forward-regexp places the point at the end of timestamp. It's a workaround that works.

It would be ideal if org-at-timestamp-p would accept multiple parameters. Current implementation is quite limited.

(defun jarfar/org-state-canceled-timestamp-toggle ()
  "Toggle active/inactive SCHEDULED or DEADLINE timestamp when switching between CANCELED and TODO state."
  (save-excursion
    (let ((state (org-get-todo-state)))
      (cond
        ((equal state "CANCELED")
          (when (and
                  (org-get-deadline-time (point))
                  (search-forward-regexp "DEADLINE: .*" nil t)
                  (org-at-timestamp-p 'agenda))
            (org-toggle-timestamp-type))
          (when (and
                  (org-get-scheduled-time (point))
                  (search-forward-regexp "SCHEDULED: .*" nil t)
                  (org-at-timestamp-p 'agenda))
            (org-toggle-timestamp-type)))
        ((equal state "TODO")
          (when (and
                  (org-get-deadline-time (point))
                  (search-forward-regexp "DEADLINE: .*" nil t)
                  (equal (char-to-string (char-before)) "]"))
            (org-toggle-timestamp-type))
          (when (and
                  (org-get-scheduled-time (point))
                  (search-forward-regexp "SCHEDULED: .*" nil t)
                  (equal (char-to-string (char-before)) "]"))
            (org-toggle-timestamp-type)))))
    (when (equal (buffer-name (current-buffer)) "*Org Agenda*")
      (with-current-buffer "*Org Agenda*" (org-agenda-redo)))))

(add-hook 'org-after-todo-state-change-hook 'jarfar/org-state-canceled-timestamp-toggle)

2
  • The best place (the only place) to suggest changes to the internals of Org mode is the mailing list. You might want to suggest improvements to org-at-timestamp-p there.
    – NickD
    Jul 30, 2020 at 20:02
  • @NickD thanks for suggestion, I send a feature request.
    – Navidot
    Aug 2, 2020 at 11:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.