1

I am bad at elisp. I am trying to return to follow the idea of just getting everything from the orgfile, then pass it to R code to do easier analysis for me.

This works to generate only tags table

#+name: orgtable
#+begin_src emacs-lisp
(let (orgtable)
  (org-map-entries
   (lambda ()
     (dolist (tag (org-get-tags))
       (push (list tag) orgtable))))
  orgtable)
#+end_src

#+begin_src R :var orgtable=orgtable
table(orgtable)

#+end_src

The above snippet works good. But I am trying to make a full table of the following columns

* TODO Task 1  :tag1:
 deadline:1-9-2021
* Waiting Task2
** DONE subtask :tag2:
::LOGBOOK::
completed: 7-7-2020
clock: start time- endtime => 2hours

#+begin_src
;;some script
#+End_src

#+ results
todo:task name:tags: schedule:deadline: clock: completed:
-----------------------------------------------------------------------
todo: task1   : tag1:        :1-9-2021:     :
waiting: task2:     :        :        :     :
done: subtask : tag2:        :        : 2hrs: 7-7-2020

I just don't know how to nest all of that in elisp code something like:

#+begin_src emacs-lisp
(let (orgtable)
  (org-map-entries
   (lambda ()
     (dolist (tag '((org-get-tags)
                    (org-get-todo-state)
                    (org-get-property-block)
                    ))
       (push (list tag) orgtable))))
  orgtable)
#+end_src

This just fails and not evaluated. Also it would be nice if I can extract every property on it's own column.

3
  • What does each row of your table represent? All the info from one headline item? It would help if you added to your question an example Org mode file with a couple of entries, each containing the essential things you want to tabulate. Also add to your question the table that you expect to get from that example file. – NickD Jul 21 '20 at 11:24
  • @NickD Thank you, I have just clarifyed with example – Omar113 Jul 21 '20 at 12:26
2

Here's an example Org file (based on what you provided but fixed up for syntax etc). It does not contain everything you want, but it does most of it - if I find time, I might come back for the rest:

#+TODO: TODO WAITING | DONE
#+STARTUP: logdrawer logdone

* TODO Task 1                                              :tag1:tag2:
DEADLINE: <2020-07-21 Tue>
 
* WAITING Task2
SCHEDULED: <2020-07-21 Tue>

** DONE subtask                                            :tag2:tag3:
CLOSED: [2020-07-21 Tue 15:50]

:LOGBOOK:
CLOCK: [2020-07-21 Tue 15:47]--[2020-07-21 Tue 15:49] =>  0:02
:END:


* COMMENT Code
#+name: tags
#+begin_src emacs-lisp
  (defun entry-get (prop)
     (or (org-entry-get (point) prop) ""))

  (defun ndk/entries-table ()
     (interactive)
     (let ((tbl '(hline ("Name" "TODO" "Tags" "Scheduled" "Deadline" "Clock" "Closed"))))
       (org-clock-sum)
       (org-map-entries
        (lambda ()
          (push (list (entry-get "ITEM")
                      (entry-get "TODO")
                      (entry-get "TAGS")
                      (entry-get "SCHEDULED")
                      (entry-get "DEADLINE")
                      (entry-get "CLOCKSUM")
                      (entry-get "CLOSED"))
                      tbl))
        t
        'file
        'comment)
       (reverse tbl)))

   (ndk/entries-table)
#+end_src

#+RESULTS: tags
| Name    | TODO    | Tags        | Scheduled        | Deadline         | Clock | Closed                 |
|---------+---------+-------------+------------------+------------------+-------+------------------------|
| Task 1  | TODO    | :tag1:tag2: |                  | <2020-07-21 Tue> |       |                        |
| Task2   | WAITING |             | <2020-07-21 Tue> |                  |  0:02 |                        |
| subtask | DONE    | :tag2:tag3: |                  |                  |  0:02 | [2020-07-21 Tue 15:50] |

Some notes:

  • I've added a #+TODO: setting, defining the TODO states, to make the file self-contained.
  • I have not worried about the LOGBOOK stuff yet: that needs fixing up, both in the file and in the code.
  • I've marked the Code section as a COMMENT and I make sure in the code to skip COMMENTed sections from processing.
  • The call to org-map-entries is limited to the current file and is instructed to skip COMMENT sections.
  • The table is initialized with the column labels and a separator (see next item for why they are in the "wrong" order).
  • We push new elements to the front of the table, so at the end we need to reverse it.
  • If something is missing, it is shown in the table as nil because that's what org-entry-get returns. We can replace those calls with (or (org-entry-get (point) "....") "") to make it return an empty string instead.
  • The special properties I use are documented here where you may find other interesting ones.

EDIT: Added the following changes:

  • Added CLOCK and CLOSED entries in the file and the corresponding entries in the table. For the clock times to be shown correctly, you need to run the function org-clock-sum in the buffer before you try to retrieve the CLOCKSUM property, so I added a call to it.
  • Added a small wrapper around org-entry-get to deal with the "nil vs empty string" problem above.
  • Made the table production code into a function ndk/entries-table and added a call to it in the source block to produce the table.

I believe this completes everything you asked for in the original question.

For the question in your comment, there are a couple of ways of dealing with it: probably the easiest is to leave everything as is, but change the ndk/entries-table function to take an argument, either a filename or a buffer. We then do everything in that buffer (but still produce the output in *this* buffer). Here's an implementation (for the whole file: you can't pick just a headline with this version, but I probably won't be able to do that any time soon - the implementation could be something like this though: make the headline a second optional argument, search in the chosen buffer for the desired headline, make sure you are in the right place, then call org-map-enrieswith atreeargument instead of afileargumentorg-map-entries` is nothing if not flexible ;-) ):

#+name: tags
#+begin_src emacs-lisp
  (defun entry-get (prop)
     (or (org-entry-get (point) prop) ""))

  (defun ndk/entries-table (&optional file-or-buffer)
     (interactive)
     (cond
      ((null file-or-buffer)
       ;; just use the current buffer
       )
      ((bufferp file-or-buffer)
       (set-buffer file-or-buffer))
      (t
       (set-buffer (find-file-noselect file-or-buffer))))
     (let ((tbl '(hline ("Name" "TODO" "Tags" "Scheduled" "Deadline" "Clock" "Closed"))))
       (org-clock-sum)
       (org-map-entries
        (lambda ()
          (push (list (entry-get "ITEM")
                      (entry-get "TODO")
                      (entry-get "TAGS")
                      (entry-get "SCHEDULED")
                      (entry-get "DEADLINE")
                      (entry-get "CLOCKSUM")
                      (entry-get "CLOSED"))
                      tbl))
        t
        'file
        'comment)
       (reverse tbl)))

   (ndk/entries-table "./bar.org")
#+end_src

#+RESULTS: tags
| Name              | TODO | Tags        | Scheduled        | Deadline         | Clock | Closed                 |
|-------------------+------+-------------+------------------+------------------+-------+------------------------|
| Task bar1         | TODO | :tag1:tag2: |                  | <2020-07-21 Tue> |       |                        |
| WAITING Task bar2 |      |             | <2020-07-21 Tue> |                  |  0:02 |                        |
| subtask bar       | DONE | :tag2:tag3: |                  |                  |  0:02 | [2020-07-21 Tue 15:50] |

BTW bar.org is more or less a copy of the original file with the titles changed, and no code included.

5
  • Thank you so much for your effort, that was exactly what I was looking for so I can get out of emacs and have more flexability to pass for python or R – Omar113 Jul 21 '20 at 18:16
  • I have just few other thought; Can I run get for another file to specific headline and it's subheadlines. In other words, if I have file A with this script, can I get entries from another file B specifically, the subheadlines of a certain headline?! – Omar113 Jul 21 '20 at 18:32
  • Added the missing stuff (see the EDIT section in the answer for the notes on what changed). In general, it is preferred if you ask one question and you don't ask additional questions in the comments: you are encouraged to open a new question. However, you get the benefit of the doubt as a new user: I'll come back and answer the additional question this time (but it may take me a day or two). But remember this for next time! – NickD Jul 21 '20 at 20:45
  • Thank you so much. This helped me alot – Omar113 Jul 22 '20 at 2:33
  • You are welcome. I added a note with a suggested implementationf ot the headline-in-file part of your question. – NickD Jul 22 '20 at 2:49

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.