2

I'm trying to create a clocktable that starts recording working time at the date of the last commit. So far I've got a src block and I'm satisfied with the resulting date, I'd like to include this date as the :tstart argument by calling the function.

#+NAME: commit_date
#+BEGIN_SRC emacs-lisp :exports none :tangle no
  (shell-command-to-string "git log -1 --format=%cd --date=format:\"<%Y-%m-%d %a %H:%M>\"")
#+END_SRC

#+RESULTS: commit_date
: <2018-02-09 ven. 10:11>

#+BEGIN: clocktable :maxlevel 3 :tstart (call_commit_date()) :narrow 90 :compact

#+END:

When I try to update the clocktable I get "Format specifier doesn't match argument type"

What am I doing wrong?

2
  • Your problem is that call_commit_date() is not evaluated. org-clock-get-table-data just gets a list (call_commit_date nil) as (plist-get params :tstart) and not a string as you expect. It is not the same as for the :var header arguments of source code blocks.
    – Tobias
    Feb 9, 2018 at 17:20
  • Do you think there is a way to do what I'm trying to accomplish?
    – Frabo
    Feb 9, 2018 at 17:45

1 Answer 1

2

The following elisp code defines a new dynamic block type babel.

Babel dblocks resolve source code block references in the values of block heading properties. The syntax is:

#+begin babel :dblock ACTUAL-TYPE :PROP1 VAL1 :PROP2 VAL2 ...
...
#+end

This babel block resolves references in the values VAL1, VAL2, ... and delegates the remaining work to the following dynamic block. Thereby the source block references in VAL1, VAL2, ... are already resolved.

#+begin ACTUAL-TYPE :PROP1 VAL1 :PROP2 VAL2 ...
...
#+end

If the elisp snippet proves useful for you install it in your init file.

(defun plist-remove (plist &rest props)
  "Return a copy of PLIST without property PROP."
  (setq plist (cl-copy-list plist))
  (dolist (prop props)
    (let ((place (plist-member plist prop)))
      (if (cddr place)
      (progn
        (setcar place (cl-caddr place))
        (setcdr place (cl-cdddr place)))
    (let ((n (length plist)))
      (if (= n 2)
          (setq plist nil)
        (setf (nthcdr (- n 2) plist) nil))))))
  plist)

(defun t-org-resolve-refs (expr)
  "Resolve references to source blocks in EXPR."
  (if (memq expr '(t nil))
      expr
    (cdr (org-babel-ref-parse (format "_=%s" expr)))))

(defun org-dblock-write:babel (params)
  "Add support for babel dblocks resolving refs in PARAMS.

#+begin babel :dblock ACTUAL-TYPE :PROP1 VAL1 :PROP2 VAL2 ...
...
#+end

babel blocks resolve references in the values VAL1, VAL2, ...
and delegate the remaining work to the dynamic block

#+begin ACTUAL-TYPE :PROP1 VAL1 :PROP2 VAL2 ...
...
#+end
"
  (let* ((dblock (plist-get params :dblock))
     (dblock-name (symbol-name dblock))
     (content (plist-get params :content))
     (params-rest params)
     (fun-name (concat "org-dblock-write:" dblock-name))
     (fun (intern-soft fun-name)))
    (cl-assert dblock nil "\"#+begin babel\" requires a \":dblock\" argument (see doc for `org-dblock-write:babel')")
    (cl-assert fun nil "Dblocks of type \"%s\" do not have a write function `%s'" dblock-name fun-name)
    (setq params-rest (plist-remove params-rest :name :dblock :content))
    (cl-loop for pair on params-rest by #'cddr do
         (setcar (cdr pair) (t-org-resolve-refs (cadr pair))))
    (plist-put params-rest :name dblock)
    (funcall fun params-rest)))

Tested with:

  • emacs-version 25.1.50
  • org-version 9.1.6

and the following clocktable block:

* Some Header
CLOCK: [2018-02-09 Fri 8:00]--[2018-02-09 Fri 16:00]
#+NAME: commit_date
#+BEGIN_SRC emacs-lisp :exports none :tangle no :dir ~/tmp/elgrep
(shell-command-to-string "git log -1 --format=%cd --date=format:\"<%Y-%m-%d %a %H:%M>\"")
#+END_SRC

#+RESULTS: commit_date
: <2018-02-04 Sun 03:25>

#+BEGIN: babel :dblock clocktable :maxlevel 3 :tstart commit_date :narrow 88 :compact nil

#+END:

Note that the header arguments of a dynamic babel block must form a valid alist. That is the reason why I added a nil at the end.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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