emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] scratch/org-edna 37e9b58 50/72: Fixed chain-find and planning act


From: Ian Dunn
Subject: [elpa] scratch/org-edna 37e9b58 50/72: Fixed chain-find and planning actions
Date: Sun, 21 May 2017 21:11:26 -0400 (EDT)

branch: scratch/org-edna
commit 37e9b58e8d86d61c9b43d21066122b7d6b0a5683
Author: Ian D <address@hidden>
Commit: Ian D <address@hidden>

    Fixed chain-find and planning actions
    
    * org-edna.el (org-edna-finder/chain-find): Fixed to match org-depend.el
      (org-edna--handle-planning): Fix to recognize when a time was used.
    
    * org-edna.org: Documented planning actions.
    
    * org-edna-tests.el: Added tests for planning.
    
    * org-edna-tests.org: Added planning test entry.
---
 org-edna-tests.el  |  64 ++++++++++++++++++++++
 org-edna-tests.org |   5 ++
 org-edna.el        |  40 ++++++++++----
 org-edna.org       | 153 +++++++++++++++++++++++++++++++++++++++++++++--------
 4 files changed, 228 insertions(+), 34 deletions(-)

diff --git a/org-edna-tests.el b/org-edna-tests.el
index 2a523c9..14c0caa 100644
--- a/org-edna-tests.el
+++ b/org-edna-tests.el
@@ -108,6 +108,10 @@
 (defconst org-edna-test-file
   (expand-file-name "org-edna-tests.org" org-edna-test-dir))
 
+;; Jan 15, 2000; chosen at random
+(defconst org-edna-test-time
+  (encode-time 0 0 0 15 1 2000))
+
 
 ;; Finders
 
@@ -161,8 +165,68 @@
       (org-edna-action/todo nil "DONE")
       (should (string-equal (org-entry-get nil "TODO") "DONE"))
       (org-edna-action/todo nil "TODO")
+      (should (string-equal (org-entry-get nil "TODO") "TODO"))
+      (org-edna-action/todo nil 'DONE)
+      (should (string-equal (org-entry-get nil "TODO") "DONE"))
+      (org-edna-action/todo nil 'TODO)
       (should (string-equal (org-entry-get nil "TODO") "TODO")))))
 
+(ert-deftest org-edna-action-scheduled/wkdy ()
+  ;; Override `current-time' so we can get a deterministic value
+  (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time))
+             (org-agenda-files `(,org-edna-test-file))
+             (target (org-id-find "0d491588-7da3-43c5-b51a-87fbd34f79f7" t)))
+    (org-with-point-at target
+      (org-edna-action/scheduled nil "Mon")
+      (should (string-equal (org-entry-get nil "SCHEDULED")
+                            "<2000-01-17 Mon>"))
+      (org-edna-action/scheduled nil 'rm)
+      (should (not (org-entry-get nil "SCHEDULED")))
+      (org-edna-action/scheduled nil "Mon 9:00")
+      (should (string-equal (org-entry-get nil "SCHEDULED")
+                            "<2000-01-17 Mon 09:00>"))
+      (org-edna-action/scheduled nil 'rm)
+      (should (not (org-entry-get nil "SCHEDULED"))))))
+
+(ert-deftest org-edna-action-scheduled/cp ()
+  ;; Override `current-time' so we can get a deterministic value
+  (let* ((org-agenda-files `(,org-edna-test-file))
+         (target (org-id-find "0d491588-7da3-43c5-b51a-87fbd34f79f7" t))
+         (source (org-id-find "97e6b0f0-40c4-464f-b760-6e5ca9744eb5" t))
+         (pairs '((cp . rm) (copy . remove) ("cp" . "rm") ("copy" . 
"remove"))))
+    (org-with-point-at target
+      (dolist (pair pairs)
+        (message "Pair: %s" pair)
+        (org-edna-action/scheduled source (car pair))
+        (should (string-equal (org-entry-get nil "SCHEDULED")
+                              "<2000-01-15 Sat 00:00>"))
+        (org-edna-action/scheduled source (cdr pair))
+        (should (not (org-entry-get nil "SCHEDULED")))))))
+
+(ert-deftest org-edna-action-scheduled/inc ()
+  ;; Override `current-time' so we can get a deterministic value
+  (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time))
+             (org-agenda-files `(,org-edna-test-file))
+             (target (org-id-find "97e6b0f0-40c4-464f-b760-6e5ca9744eb5" t)))
+    (org-with-point-at target
+      ;; Time started at Jan 15, 2000
+      ;; Increment 1 minute
+      (org-edna-action/scheduled nil "+1M")
+      (should (string-equal (org-entry-get nil "SCHEDULED")
+                            "<2000-01-15 Sat 00:01>"))
+      (org-edna-action/scheduled nil "-1M")
+      (should (string-equal (org-entry-get nil "SCHEDULED")
+                            "<2000-01-15 Sat 00:00>"))
+      (org-edna-action/scheduled nil "+1d")
+      (should (string-equal (org-entry-get nil "SCHEDULED")
+                            "<2000-01-16 Sun 00:00>"))
+      (org-edna-action/scheduled nil "++1h")
+      (should (string-equal (org-entry-get nil "SCHEDULED")
+                            "<2000-01-15 Sat 01:00>"))
+      (org-edna-action/scheduled nil "2000-01-15 Sat 00:00")
+      (should (string-equal (org-entry-get nil "SCHEDULED")
+                            "<2000-01-15 Sat 00:00>")))))
+
 
 ;; Conditions
 
diff --git a/org-edna-tests.org b/org-edna-tests.org
index 6f3341c..666ec1e 100644
--- a/org-edna-tests.org
+++ b/org-edna-tests.org
@@ -28,6 +28,11 @@ along with this program.  If not, see 
<http://www.gnu.org/licenses/>.
 :ID:       b010cbad-60dc-46ef-a164-eb155e62cbb2
 :LOGGING:  nil
 :END:
+** TODO ID Heading 3
+SCHEDULED: <2000-01-15 Sat 00:00>
+:PROPERTIES:
+:ID:       97e6b0f0-40c4-464f-b760-6e5ca9744eb5
+:END:
 ** Scheduled Headings
 *** TODO Scheduled Heading 1
 SCHEDULED: <2017-01-01 Sun>
diff --git a/org-edna.el b/org-edna.el
index 73d2bd0..da8747a 100644
--- a/org-edna.el
+++ b/org-edna.el
@@ -360,9 +360,15 @@ IDS are all UUIDs as understood by `org-id-find'."
 
 (defun org-edna-finder/chain-find (&rest options)
   ;; sortfun - function to use to sort elements
-  ;; filterufn - Function to use to filter elements
+  ;; filterfun - Function to use to filter elements
   ;; Both should handle positioning point
-  (let (targets sortfun filterfun)
+  (let (targets
+        sortfun
+        ;; From org-depend.el:
+        ;; (and (not todo-and-done-only)
+        ;;      (member (second item) org-done-keywords))
+        (filterfun (lambda (target)
+                     (member (org-entry-get target "TODO") 
org-done-keywords))))
     (dolist (opt options)
       (pcase opt
         ('from-top
@@ -374,13 +380,17 @@ IDS are all UUIDs as understood by `org-id-find'."
         ('no-wrap
          (setq targets (org-edna-finder/rest-of-siblings)))
         ('todo-only
+         ;; Remove any entry without a TODO keyword, or with a DONE keyword
          (setq filterfun
                (lambda (target)
-                 (org-entry-get target "TODO"))))
+                 (let ((kwd (org-entry-get target "TODO")))
+                   (or (not kwd)
+                       (member kwd org-done-keywords))))))
         ('todo-and-done-only
+         ;; Remove any entry without a TODO keyword
          (setq filterfun
                (lambda (target)
-                 (member (org-entry-get target "TODO") org-done-keywords))))
+                 (not (org-entry-get target "TODO")))))
         ('priority-up
          (setq sortfun
                (lambda (lhs rhs)
@@ -408,7 +418,7 @@ IDS are all UUIDs as understood by `org-id-find'."
     (when (and targets sortfun)
       (setq targets (seq-sort sortfun targets)))
     (when (and targets filterfun)
-      (setq targets (seq-filter filterfun targets)))
+      (setq targets (seq-remove filterfun targets)))
     (when targets
       (list (seq-elt 0 targets)))))
 
@@ -446,24 +456,32 @@ IDS are all UUIDs as understood by `org-id-find'."
                      ("h" . hour)
                      ("M" . minute))))
     (cond
-     ((member arg '('rm 'remove "rm" "remove"))
+     ((member arg '(rm remove "rm" "remove"))
       (org-add-planning-info nil nil type))
-     ((member arg '('cp 'copy "cp" "copy"))
+     ((member arg '(cp copy "cp" "copy"))
+      (unless last-ts
+        (error "Tried to copy but last entry doesn't have a timestamp"))
       ;; Copy old time verbatim
       (org-add-planning-info type last-ts))
      ((string-match-p "\\`[+-]" arg)
+      ;; Starts with a + or -, so assume we're incrementing a timestamp
       ;; We support hours and minutes, so this must be supported separately,
       ;; since org-read-date-analyze doesn't
-      ;; Starts with a + or -, so assume we're incrementing a timestamp
       (pcase-let* ((`(,n ,what-string ,def) (org-read-date-get-relative arg 
this-time current))
                    (ts (if def current-ts this-ts))
                    (what (cdr (assoc-string what-string type-map))))
         (org--deadline-or-schedule nil type (org-edna--mod-timestamp ts n 
what))))
      (t
       ;; For everything else, assume `org-read-date-analyze' can handle it
-      (let* ((parsed-time (org-read-date-analyze arg this-time (decode-time 
this-time)))
-             (final-time (apply 'encode-time parsed-time))
-             (new-ts (format-time-string "%F %R" final-time)))
+
+      ;; The third argument to `org-read-date-analyze' specifies the defaults 
to
+      ;; use if that time component isn't specified.  Since there's no way to
+      ;; tell if a time was specified, tell `org-read-date-analyze' to use nil
+      ;; if no time is found.
+      (let* ((parsed-time (org-read-date-analyze arg this-time '(nil nil nil 
nil nil nil)))
+             (have-time (nth 2 parsed-time))
+             (final-time (apply 'encode-time (mapcar (lambda (e) (or e 0)) 
parsed-time)))
+             (new-ts (format-time-string (if have-time "%F %R" "%F") 
final-time)))
         (org--deadline-or-schedule nil type new-ts))))))
 
 (defun org-edna-action/scheduled (last-entry &rest args)
diff --git a/org-edna.org b/org-edna.org
index d225adb..5144f5a 100644
--- a/org-edna.org
+++ b/org-edna.org
@@ -118,17 +118,19 @@ scheduling another task, marking another task as TODO, or 
renaming a file.
 :END:
 #+cindex: syntax
 
-The basic syntax of Edna's commands is KEYWORD(ARG1,ARG2,...)
+Edna has its own language for commands, the basic form of which is 
KEYWORD(ARG1 ARG2 ...)
 
-KEYWORD can be any valid symbol, such as key-word, KEY_WORD, or keyword?.
+KEYWORD can be any valid lisp symbol, such as key-word, KEY_WORD, or keyword?.
 
 Each argument can be one of the following:
 
-- A symbol, such as arg or arg-1
-- A valid lisp form, such as (+ 1 2) or (or a b)
+- A symbol, such as arg or org-mode
 - A quoted string, such as "hello" or "My name is Edna"
+- A number, such as 0.5, +1e3, or -5
+- A UUID, such as c5e30c76-879a-494d-9281-3a4b559c1a3c
 
-Any quotes should be escaped (e.g. "\"\"").
+Each argument takes specific datatypes as input, so be sure to read the entry
+before using it.
 
 The parentheses can be omitted for commands with no arguments.
 * Basic Features
@@ -165,6 +167,42 @@ For example:
 
 In the above example, "Heading 5" will be blocked until "Heading 1", "Heading
 3", and "Heading 4" are marked "DONE", while "Heading 2" is ignored.
+*** chain-find
+
+chain-find(OPTION OPTION...)
+
+Identical to the chain argument in org-depend, chain-find selects its single
+target using the following method:
+
+1. Creates a list of possible targets
+2. Filters the targets from Step 1
+3. Sorts the targets from Step 2
+
+After this is finished, chain-find selects the first target in the list and
+returns it.
+
+One option from each of the following three categories may be used; if more 
than
+one is specified, the last will be used.
+
+<<Selection>>
+
+- from-top:     Select siblings of the current headline, starting at the top
+- from-bottom:  As above, but from the bottom
+- from-current: Selects siblings, starting from the headline (wraps)
+- no-wrap:      As above, but without wrapping
+
+<<Filtering>>
+
+- todo-only:          Select only targets with TODO state set that isn't a 
DONE keyword
+- todo-and-done-only: Select all targets with a TODO state set
+
+<<Sorting>>
+
+- priority-up:   Sort by priority, highest first
+- priority-down: Same, but lowest first
+- effort-up:     Sort by effort, highest first
+- effort-down:   Sort by effort, lowest first
+
 *** children
 :PROPERTIES:
 :DESCRIPTION: Find all immediate children
@@ -176,7 +214,7 @@ headline.
 In order to get all levels of children of the current headline, use the
 [[#descendants][descendants]] keyword instead.
 
-*** TODO descendants
+*** descendants
 :PROPERTIES:
 :DESCRIPTION: Find all descendants
 :CUSTOM_ID: descendants
@@ -193,8 +231,10 @@ EXAMPLE HERE
 :DESCRIPTION: Find a file by name
 :END:
 
-The ~file~ finder finds a single file.  The returned target will be the minimum
-point in the file.
+file(FILE)
+
+The ~file~ finder finds a single file, specified as a string.  The returned 
target
+will be the minimum point in the file.
 
 Note that with the default condition, ~file~ won't work.  See 
[[#conditions][conditions]] for how
 to set a different condition.  For example:
@@ -208,9 +248,6 @@ to set a different condition.  For example:
 
 Here, "Test" will block until myfile.org is clear of headlines.
 
-WARNING: Make sure to quote the file name.  If not, Edna will interpret it as
-"myfile\\.org" and create that file.
-
 *** first-child
 :PROPERTIES:
 :CUSTOM_ID: first-child
@@ -231,7 +268,7 @@ number of UUIDs may be specified.  For example:
 #+BEGIN_EXAMPLE
 ,* TODO Test
   :PROPERTIES:
-  :BLOCKER:  
ids(62209a9a-c63b-45ef-b8a8-12e47a9ceed9,6dbd7921-a25c-4e20-b035-365677e00f30)
+  :BLOCKER:  ids(62209a9a-c63b-45ef-b8a8-12e47a9ceed9 
6dbd7921-a25c-4e20-b035-365677e00f30)
   :END:
 #+END_EXAMPLE
 
@@ -239,19 +276,23 @@ Here, "Test" will block until the headline with ID
 62209a9a-c63b-45ef-b8a8-12e47a9ceed9 and the headline with ID
 6dbd7921-a25c-4e20-b035-365677e00f30 are set to "DONE".
 
+Note that UUIDs need not be quoted; Edna will handle that for you.
+
 *** match
 :PROPERTIES:
 :CUSTOM_ID: match
 :DESCRIPTION: Good old tag matching
 :END:
 
+match(MATCH-STRING SCOPE SKIP)
+
 The ~match~ keyword will take any arguments that ~org-map-entries~ usually 
takes.
 In fact, the arguments to ~match~ are passed straight into ~org-map-entries~.
 
 #+BEGIN_EXAMPLE
 ,* TODO Test
   :PROPERTIES:
-  :BLOCKER:  match(test&mine,agenda)
+  :BLOCKER:  match("test&mine" agenda)
   :END:
 #+END_EXAMPLE
 
@@ -265,14 +306,46 @@ argument.
 :PROPERTIES:
 :CUSTOM_ID: next-sibling
 :END:
+
+The ~next-sibling~ keyword returns the next sibling of the current heading, if
+any.
+
 *** olp
 :PROPERTIES:
 :CUSTOM_ID: olp
 :END:
+
+olp(FILE OLP)
+
+Finds the heading given by OLP in FILE.  Both arguments are strings.
+
+#+BEGIN_EXAMPLE
+,* TODO Test
+  :PROPERTIES:
+  :BLOCKER:  olp("test.org" "path/to/heading")
+  :END:
+#+END_EXAMPLE
+
+"Test" will block if the heading "path/to/heading" in "test.org" is not DONE.
+
 *** org-file
 :PROPERTIES:
 :CUSTOM_ID: org-file
 :END:
+
+org-file("FILE")
+
+A special form of ~file~, ~org-file~ will find FILE in ~org-directory~.
+
+#+BEGIN_EXAMPLE
+,* TODO Test
+  :PROPERTIES:
+  :BLOCKER:  org-file("test.org")
+  :END:
+#+END_EXAMPLE
+
+Note that the file still requires an extension.
+
 *** parent
 :PROPERTIES:
 :CUSTOM_ID: parent
@@ -281,36 +354,70 @@ argument.
 :PROPERTIES:
 :CUSTOM_ID: previous-sibling
 :END:
+*** rest-of-siblings
+
+Finds the remaining siblings on the same level as the current headline.
+
 *** self
 :PROPERTIES:
 :CUSTOM_ID: self
 :END:
+
+Returns the current headline.
+
 *** siblings
 :PROPERTIES:
 :CUSTOM_ID: siblings
 :END:
+*** siblings-wrap
+
+Finds the siblings on the same level as the current headline, wrapping when it
+reaches the end.
+
 ** Actions
 Once Edna has collected its targets for a trigger, it will perform actions on
 them.
 *** Scheduled/Deadline
-- PLANNING(WKDY[ TIME]) -> Set PLANNING to following weekday WKDY at TIME
-- PLANNING(rm|remove) -> Remove PLANNING info
-- PLANNING([copy|cp]) -> Copy timestamp verbatim
-- PLANNING([+|-][+|-]NTHING) -> Increment(+) or decrement(-) source (double) 
or current (single) PLANNING by N THINGs
+:PROPERTIES:
+:CUSTOM_ID: planning
+:END:
+
+scheduled(OPTIONS)
+deadline(OPTIONS)
+
+There are several forms that the planning keywords can take:
+
+- PLANNING("WKDY[ TIME]")
+
+  Sets PLANNING to the following weekday WKDY at TIME.  If TIME is not
+  specified, only a date will be added to the target.
+
+  WKDY is a weekday or weekday abbreviation (see ~org-read-date~)
+
+  TIME is a time string HH:MM, etc.
+
+- PLANNING(rm|remove)
+
+  Remove PLANNING from all targets.  The argument to this form may be either a
+  string or a symbol.
+
+- PLANNING(copy|cp)
 
-PLANNING is either scheduled or deadline
+  Copy PLANNING info verbatim from the current headline to all targets.  The
+  argument to this form may be either a string or a symbol.
 
-WKDY is a weekday or weekday abbreviation (see org-read-date)
+- PLANNING("[+|-][+|-]NTHING")
 
-TIME is a time string HH:MM, etc.
+  Increment(+) or decrement(-) source (double) or current (single) PLANNING by 
N
+  THINGs
 
-N is an integer
+  N is an integer
 
-THING is one of y (years), m (months), d (days), h (hours), or M (minutes)
+  THING is one of y (years), m (months), d (days), h (hours), or M (minutes)
 
 Examples:
 
-scheduled(Mon 09:00) -> Set SCHEDULED to the following Monday at 9:00
+scheduled("Mon 09:00") -> Set SCHEDULED to the following Monday at 9:00
 *** Todo State
 todo(NEW-STATE)
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]