How to test for org-todo state “xyz” with deadline not equal to today

二次信任 提交于 2019-12-24 01:47:38

问题


What is the best way, please, to test for the existence of a specific todo state and a deadline that is not equal to today?

org-state is a "[h]ook which is run after the state of a TODO item was changed". So unless I'm actually changing the state of a todo, I don't think I can use (string-equal org-state "Next Action"). Each of my string-equal lines of code listed below are rejected: Symbol's value as variable is void: org-todo and org-deadline. The deadline is a line that appears underneath the todo state, so that may also pose a problem when testing for the existence of both conditions.

(defun if-next-action-not-today-then-promote ()

(interactive)

    (goto-char (point-min))

    (while

    (re-search-forward "^\*\* Next Action" nil t)

        (when (and (string-equal org-todo "Next Action") (not (string-equal org-deadline "<%<%Y-%m-%d %a>>")) )

        (message "You have satisfied the two conditions . . . proceeding.")

        (org-todo "Active")  ;; change state to active

        (org-deadline nil "<%<%Y-%m-%d %a>>") ;; change deadline to today

         )

    )

)

Sample *.org configuration file.

* TASKS

  ** Active [#A] First task due today. :lawlist:
     DEADLINE: <2013-07-11 Thu >

  ** Active [#A] Second task due today. :lawlist:
     DEADLINE: <2013-07-11 Thu >

  ** Next Action [#E] Test One -- make Active with deadline today. :lawlist:
     DEADLINE: <2013-07-31 Wed >

  ** Next Action [#E] Test Two -- make Active with deadline today. :lawlist:
     DEADLINE: <2013-07-31 Wed >

EDIT: The following is a modification of the function proposed by Jonathan Leech-Pepin in his answer further down below. In the first draft of the answer, I was unable to obtain anything but nil from the variable deadline due to a problem with (org-element-timestamp-interpreter . . . nil) -- completely eliminating that reference appears to correct the issue. I set up messages along the way so that I could better understand what was happening. I used if instead of unless because I wanted an else message to let me know that the conditions were not met but that the function was nevertheless working correctly. I've run several tests, including wrapping it into an re-search-forward type function and it works very nicely -- a wrapped function can be done several ways, but that is beyond the scope of this thread -- e.g., (&optional from-state to-state) and (interactive) and then (setq . . .) further down; or (from-state to-state) and (interactive (list (setq . . .).

(defun zin/org-test-deadline (from-state to-state)

"Change headline from FROM-STATE to TO-STATE if the deadline is not already set to today."

  (interactive "sChange from state: \nsChange to state: ")

    (unless (org-at-heading-p)
      (org-back-to-heading))

    (let* (

      (element (org-element-at-point))

      (todo-state (org-element-property :todo-keyword element))

      ;; "ignore-errors" avoids throwing an error message if there is no deadline.
      (deadline
        (ignore-errors
        (time-to-days
        (org-time-string-to-time
        (org-element-property :deadline element) ))))

      (today (time-to-days (current-time))) )

    (message "This is the element variable:  %s" element)

    (message "This is the today variable:  %s" today)

    (message "This is the deadline variable:  %s" deadline)

    (message "This is the todo-state variable:  %s" todo-state)

    (message "This is the from-state variable:  %s" from-state)

    (message "This is the to-state variable:  %s" to-state)

    (if (not (eq today deadline))
      (message "The deadline is not today.")
      (message "Today is the deadline."))

    (if (and
      (not (eq today deadline)) ;; condition -- deadline not equal to today
      (string= todo-state from-state) ) ;; condition -- todo-state equals from-state
        (progn ;; Process following list if conditions were met.
          (org-todo to-state)
          (org-deadline nil ".")
          (message "The conditions were met, so we did everything that was required.") )
      (message "The conditions were not met, so nothing has been done."))
  ))

回答1:


As long as you are using Org 7.9.2 or greater the following should work. I tested it as well as I could by adjusting deadlines and todo states.

(defun zin/org-test-deadline (from-state to-state)
  "Change headline from FROM-STATE to TO-STATE if the deadline is
not already set to today."
  (interactive "sChange from state: \nsChange to state: ")
  (unless (org-at-heading-p)
    (org-back-to-heading))
  (let* ((element (org-element-at-point))
         (todo-state (org-element-property :todo-keyword
                                           element))
         ;; Do not give an error if there is no deadline
         (deadline (ignore-errors
                     (time-to-days
                      (org-time-string-to-time
                       (org-element-timestamp-interpreter
                        (org-element-property :deadline
                                              element) nil)))))
         (today (time-to-days (current-time))))
    (unless (or
             ;; Is there a deadline
             (not deadline)
             ;; Is the deadline today
             (eq today deadline)
             ;; Is the todo state the wrong one
             (not (string= todo-state from-state)))
      (org-todo to-state)
      (org-deadline nil "."))))

You can then bind this or wrap it in a function that defines from-state and to-state. It will also prompt for the two states if called interactively.



来源:https://stackoverflow.com/questions/17602498/how-to-test-for-org-todo-state-xyz-with-deadline-not-equal-to-today

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!