1

I have this code:

(defun org-get-logbook-notes ()
  (save-excursion
    (unless (org-at-heading-p)
      (outline-previous-heading))
    (when (re-search-forward ":LOGBOOK:" (save-excursion
                                           (outline-next-heading)
                                           (point))
                             t)
      (let* ((elt (org-element-property-drawer-parser nil))
             (beg (org-element-property :contents-begin elt))
             (end (org-element-property :contents-end elt)))
        (buffer-substring-no-properties beg end)))))

(require 's)

(defun my/org-rotten-set ()
(interactive "P")
(setq lognotes (org-get-logbook-notes))
(setq numresched (number-to-string (s-count-matches "Rescheduled from" lognotes))) 
(org-entry-put nil "ROTTEN" numresched ))

What it should do is simply the following task:

  • Get the contents of the :LOGBOOK: drawer
  • Count how many times the string "Rescheduled from" occurs
  • Transform this into a number and create a property "ROTTEN" with this number as a value

If I use IELM, place the point inside a single entry in my orgfile and execute

ELISP> (my/org-rotten-set)

This works perfectly fine. The occurences of "Rescheduled from" will be count, the "ROTTEN" property will be created.

Now if I try to use this function together with org-map-entries it doesn't work.

ELISP> (org-map-entries 'my/org-rotten-set)
*** Eval error ***  Wrong type argument: char-or-string-p, nil

What am I doing wrong here? It seems to be related to the org-get-logbook-notes function that I defined a the beginning, but I have no idea why?

1

org-map-entries operates on whatever you specify as its SCOPE (see the doc string for details). Since you have not expicitly specified the scope in your call, it is nil: that means it operates on the current buffer (respecting the restriction, if any - but that's unimportant here). The main point is that you are executing it in the IELM buffer, so that's the current buffer, not your Org mode file.

Try

(with-current-buffer (get-buffer "name of your Org mode file here")
   (org-map-entries #'my/org-rotten-set))

But there is a problem in my/org-rotten-set that you need to fix: if there is no LOGBOOK drawer in an entry, (org-get-logbook-notes) will return nil and that will cause s-count-matches to give you the error you get: " (wrong-type-argument char-or-string-p nil)". You need to check the return value and do nothing if it is nil:

(defun my/org-rotten-set ()
  (interactive)
  (setq lognotes (org-get-logbook-notes))
  (when lognotes
    (setq numresched (number-to-string (s-count-matches "Rescheduled from" lognotes))) 
    (org-entry-put nil "ROTTEN" numresched )))

It's also better to use let-bound variables in the function, rather than using setq and global variables :

(defun my/org-rotten-set ()
  (interactive)
  (let ((lognotes (org-get-logbook-notes)))
    (when lognotes
      (org-entry-put nil "ROTTEN" (number-to-string 
                                    (s-count-matches "Rescheduled from" lognotes))))))

Another (less likely) problem is that if the string ":LOGBOOK:" occurs in the file (outside the context of a LOGBOOK drawer), org-get-logbook-entries might get confused. I'll leave that problem for the interested reader to pursue :-)

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.