org-wild-notifier.el icon indicating copy to clipboard operation
org-wild-notifier.el copied to clipboard

Support for repeated tasks

Open xzebra opened this issue 5 years ago • 8 comments

I'm creating this issue as a proposal.

As I mentioned in https://github.com/akhramov/org-wild-notifier.el/issues/30#issuecomment-722579110, repeated tasks format is not parsed correctly, e.g. <2020-09-17 17:50-20:50 .+1w> is parsed by org-parse-time-string as if it was <2020-09-17 17:50>.

xzebra avatar Nov 05 '20 21:11 xzebra

org-time-string-to-absolute gives us the closest date to the second argument if there is a specifier for a cyclic time stamp.

(org-time-string-to-absolute "<2020-09-17 Thu 19:56-20:50 .+1w>" "<2020-11-05>")
(org-time-string-to-absolute "<2020-11-05 Thu 19:56-20:50 .+1w>" "<2020-11-05>")

Both lines give us the value of parsing "<2020-11-05 Thu 19:56>".

By using org-format-time-string, we can get the current time formatted as org format requires.

(org-time-string-to-absolute "<2020-09-17 Thu 19:56-20:50 .+1w>"
                             (org-format-time-string "<%Y-%m-%d>"))

In order to have the same result as the mentioned line, we can use org-time-from-absolute to convert:

(org-time-from-absolute
 (org-time-string-to-absolute "<2020-09-17 Thu 19:56-20:50 .+1w>"
                              (org-format-time-string "<%Y-%m-%d>")))

With all of this together, we could integrate it as:

(defun org-wild-notifier--extract-time (marker)
  "Extract timestamps from MARKER.
Timestamps are extracted as cons cells.  car holds org-formatted
string, cdr holds time in list-of-integer format."
  (-non-nil
   (--map
    (let* ((org-timestamp (org-entry-get marker it))
           (nearest-time (org-time-string-to-absolute org-timestamp)))
      (and org-timestamp
           (cons org-timestamp
                 (org-time-from-absolute nearest-time))))
    '("DEADLINE" "SCHEDULED" "TIMESTAMP"))))

I have tried all the functions but the last one, as I'm new to elisp and I don't know how to test or debug it. I'm open to suggestions.

xzebra avatar Nov 05 '20 21:11 xzebra

I found org-closest-date which does the exact same thing. The problem with this two functions is that they don't look at the hour, just the day.

xzebra avatar Nov 06 '20 01:11 xzebra

As a workaround, I'm using this hacks:

I added a new function, which is the responsible of better parsing a timestamp. In case it is a cyclic timestamp, it gets the closest date cycle until today.

(defun org-wild-notifier--timestamp-parse (timestamp)
  (let ((parsed (org-parse-time-string timestamp))
        (today (org-format-time-string "<%Y-%m-%d>")))
    ;; seconds-to-time returns also milliseconds and nanoseconds so we
    ;; have to "trim" the list
    (butlast 
     (seconds-to-time
      (org-time-add
       ;; we get the cycled absolute day (not hour and minutes)
       (org-time-from-absolute (org-closest-date timestamp today 'past))
       ;; so we have to add the minutes too
       (+ (* (decoded-time-hour parsed) 3600)
          (* (decoded-time-minute parsed) 60))))
     2)
))

As org-closest-date returns the time of the absolute day (no hour or minutes considered), we have to sum the hours and minutes to the date.

After that, we change the extract time function:

(defun org-wild-notifier--extract-time (marker)
  "Extract timestamps from MARKER.
Timestamps are extracted as cons cells.  car holds org-formatted
string, cdr holds time in list-of-integer format."
  (-non-nil
   (--map
    (let ((org-timestamp (org-entry-get marker it)))
      (and org-timestamp
           (cons org-timestamp
                 (org-wild-notifier--timestamp-parse org-timestamp))))
    '("DEADLINE" "SCHEDULED" "TIMESTAMP"))))

xzebra avatar Nov 08 '20 03:11 xzebra

I am new to emacs and elisp in general. How do you implement this? In particular, how to get the org-wild-notifier to call the org-wild-notifier--extract-time function?

al23212321 avatar Nov 23 '21 05:11 al23212321

I don't know if this will be incompatible with newer versions, as I haven't updated the repo since then I wrote that a year ago. Although, this is how I did it:

I cloned the repo in my private config (locally), then I imported the package from my local copy of the repo. My import looks like this:

(use-package! org-wild-notifier
  :load-path "~/.doom.d/lisp/org-wild-notifier.el"
  :after org
  :config
  (setq org-wild-notifier-keyword-whitelist '())
  (setq org-wild-notifier-keyword-blacklist '("DONE"))
  (setq org-wild-notifier-alert-time '(5))
  (org-wild-notifier-mode)
)

I'm using doom-emacs, so you might have to google how to import a local package with the package loader you are using.

Then you can subsitute the defun of the org-wild-notifier--extract-time function in the local repo with the one I showed.

xzebra avatar Nov 23 '21 17:11 xzebra

Sorry, guys, I'm such a mess.

akhramov avatar Nov 23 '21 19:11 akhramov

Edit: It works. Thanks @xzebra! After changing the org-wild-notifier.el, I didnt run doom build to remove the stale elc file which is required.

@xzebra Thanks for the swift reply. I tested on the latest version. On my system, seems like the hack does not have any effect. It still only show notification if the date in the timestamp matches with the current date ** Lecture <2021-11-23 Tue 12:00-15:00 .+1d> ;; No notification

** Lecture <2021-11-25 Thu 12:00-15:00 .+1d>

As a workaround, I'm using this hacks:

I added a new function, which is the responsible of better parsing a timestamp. In case it is a cyclic timestamp, it gets the closest date cycle until today.

(defun org-wild-notifier--timestamp-parse (timestamp)
  (let ((parsed (org-parse-time-string timestamp))
        (today (org-format-time-string "<%Y-%m-%d>")))
    ;; seconds-to-time returns also milliseconds and nanoseconds so we
    ;; have to "trim" the list
    (butlast 
     (seconds-to-time
      (org-time-add
       ;; we get the cycled absolute day (not hour and minutes)
       (org-time-from-absolute (org-closest-date timestamp today 'past))
       ;; so we have to add the minutes too
       (+ (* (decoded-time-hour parsed) 3600)
          (* (decoded-time-minute parsed) 60))))
     2)
))

As org-closest-date returns the time of the absolute day (no hour or minutes considered), we have to sum the hours and minutes to the date.

After that, we change the extract time function:

(defun org-wild-notifier--extract-time (marker)
  "Extract timestamps from MARKER.
Timestamps are extracted as cons cells.  car holds org-formatted
string, cdr holds time in list-of-integer format."
  (-non-nil
   (--map
    (let ((org-timestamp (org-entry-get marker it)))
      (and org-timestamp
           (cons org-timestamp
                 (org-wild-notifier--timestamp-parse org-timestamp))))
    '("DEADLINE" "SCHEDULED" "TIMESTAMP"))))

@akhramov Thanks for creating this package! Do you have a fix for this?

al23212321 avatar Nov 25 '21 04:11 al23212321

Glad to hear that!

xzebra avatar Nov 25 '21 06:11 xzebra

oh god it works! can't believe that. never been this stressed my entire life. Why hasn't this been merged? It works perfectly even two years after it has been written!

danielkrajnik avatar Jul 29 '23 12:07 danielkrajnik

seems like this was fixed.

colonelpanic8 avatar Sep 15 '23 06:09 colonelpanic8