0

I've created a diary function to allow me to record cyclic events. So something like (diary-limited-cyclic-weekday 8 '(0 3 6) 01 01 2018) will create an event for every Sunday, Wednesday, and Saturday since the start date. So in the example: the 3, 6, 7, 10, 13, 14, 17, and 20th of January 2018 should be marked with an event.

I put this function in an org file as: * Blooop <%%(diary-limited-cyclic-weekday 8 '(0 3 6) 01 01 2018)> 09:00-10:00 When I run it I get

Bad sexp at line 9 in /home/luis/Documents/org/agenda/schedule.org: (let ((entry ) (date (quote (1 1 2018)))) (diary-limited-cyclic-weekday 8 (quote (0 3 6)) 1 1 2018))

I get subsequent errors just like this except with the day in (quote (1 1 2018)) incremented by 1. For example:

Bad sexp at line 9 ... (quote 1 2 2018)...
Bad sexp at line 9 ... (quote 1 3 2018)...
...

At first this made me think that perhaps my function was too slow and because of this taking too long to return a value for a single date.

I wrote this function trying to emulate the diary-limited-cyclic function I found online.

What could be the problem with my function? Note that even when I remove the potentially complicated (> recurrences ...) sexp at the end, and expect it to just return every Sun, Wed, Sat afterwards, I get the same error.

(defun diary-limited-cyclic-weekday (recurrences weekdays m d y)
  "For use in emacs diary. Cyclic item with a limited number of occurences.
WEEKDAYS is a list of the days of the week (0-6) in which event will repeat starting on
  YYYY-MM-DD, for a total of RECURRENCES occasions."
  (let* ((today-day (calendar-day-of-week date))
         (today (calendar-absolute-from-gregorian date))
         (start (calendar-absolute-from-gregorian (list m d y)))
         (start-day (calendar-day-of-week start))
         (day-range (- today start)))

    (and (not (cl-minusp day-range)) ; not less than start day
         (cl-member today-day weekdays) ; is one of the desired weekdays
         ;; number of target weekdays in full weeks
         ;; + number of target weekdays in remainder days
         (> recurrences (+ (* (cl-list-length weekdays) (cl-mod day-range 7)) 
                           (cl-loop
                            for day from start-day to (+ start-day (cl-rem day-range 7))
                            count (cl-member day weekdays)))))))


(defun diary-limited-cyclic (recurrences interval m d y)                    
  "For use in emacs diary. Cyclic item with limited number of recurrences.    
Occurs every INTERVAL days, starting on YYYY-MM-DD, for a total of          
RECURRENCES occasions."                                                     
  (let ((startdate (calendar-absolute-from-gregorian (list m d y)))           
        (today (calendar-absolute-from-gregorian date)))                            
    (and (not (cl-minusp (- today startdate)))                                  
         (zerop (% (- today startdate) interval))                                    
         (< (floor (- today startdate) interval) recurrences))))  
  • I see that the way you use it, diary-sexp-entry is actually not used, instead org-diary-sexp-entry is used, which does more or less the same thing, except it doesn't show the actual error !! Please M-: (setq calendar-debug-sexp t) RET and then reproduce the error (you should then get a full backtrace). – Stefan Jan 18 '18 at 15:10
  • This really helped! Now that I could see the error I debugged the method and got it working. I will post the working method below. – Aquaactress Jan 18 '18 at 16:19
0

Not sure what is the probem, but (diary-limited-cyclic-weekday 8 '(0 3 6) 01 01 2018)) has an extra finbal parenthesis. Maybe that's just it (tho it's unlikely); if not, please provide the actual error message (the part after "Bad diary sexp at line NN in FOO:").

As for the date variable, it is provided by dynamic scoping. Not sure exactly where this is documented (I haven't checked the manual), but technically, the var is provided from diary-sexp-entry. It's at least mentioned in the docstring of diary-list-entries:

... Note that hook functions should not use date, but original-date. (Sexp diary entries may use date - see diary-list-sexp-entries.) ...

as well as the docstring of diary-list-sexp-entries:

... The form of a sexp diary entry is

             %%(SEXP) ENTRY

Both entry and date are available when the SEXP is evaluated. ...

  • I've added more information about the error and removed the extra parentheses as that was just a typo when writing the question. – Aquaactress Jan 18 '18 at 13:46
  • I also removed the second question as to how diary works because I realized it was problematic choosing the accepted answer when I have 2 different questions. – Aquaactress Jan 18 '18 at 14:03
0

Stefan's advice to add set the variable calendar-debug-sexp to t. Allowed me to see the full stacktrace when debugging diary-limited-cyclic-weekday.

The problems were fairly simple. calendar-day-of-the-week expected a list of the form (m d y) but I was giving date variable. I'm actually unsure as to why date works as a parameter for calendar-absolute-from-gregorian but not calendar-day-of-the-week as according to their documentation they both need a list fo the form (m d y) but I suspect the answer to this lies in the documentation Stefan referenced in his answer above.

Another change I made was change cl-mod to floor when I realized cl-mod and cl-rem both get the remainder and that to get the number of full weeks I needed the floor. Finally, I changed the (> recurrences...) to (>= recurrences...) to make sure there are a recurrences number of days chosen in the calendar instead of recurrences - 1 days.

(defun diary-limited-cyclic-weekday (recurrences weekdays m d y)
  "For use in emacs diary. Cyclic item with a limited number of occurences.
WEEKDAYS represents the days of the week in which event will repeat starting on YYYY-MM-DD, for a total of RECURRENCES occasions."
  (let* ((today-day (calendar-day-of-week date))
     (today (calendar-absolute-from-gregorian date))
     (start (calendar-absolute-from-gregorian (list m d y)))
     (start-day (calendar-day-of-week (list m d y)))
     (day-range (- today start)))

(and (not (cl-minusp day-range))
     (cl-member today-day weekdays)
     (>= recurrences (+ (* (cl-list-length weekdays) (floor day-range 7)) 
                        (cl-loop
                         for day from start-day to (+ start-day (cl-rem day-range 7))
                         count (cl-member day weekdays)))))))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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