Hi,

I have discovered that org-capture templates can't expand Lisp variabels with 
%(), only functions. Is that a bug or a feature?

In Emacs -q do:

#+begin_src emacs-lisp
(require 'org-capture)

(defun test1 ()
  (with-temp-buffer
    (org-capture-fill-template "%(default-directory)")))

;; => "%![Error: (void-function default-directory)]
;; "

(defun test2 ()
  (with-temp-buffer
    (org-capture-fill-template "%(buffer-name)")))
#+end_src

The manual says:

#+begin_quote
‘%(EXP)’
     Evaluate Elisp expression EXP and replace it with the result.  The
     EXP form must return a string.  Only placeholders pre-existing
     within the template, or introduced with ‘%[file]’, are expanded
     this way.  Since this happens after expanding non-interactive
     "%-escapes", those can be used to fill the expression.
#+end_quote


Symbolic expression are atoms or lists of symbolic expressions, so according to 
documentation I would expect EXP to be
both variables and functions, and the pair of outer parenthesis not to be the 
part of the expression itself. However, according
to current source code and the results, outer parenthesis are treated not as 
markers where the expression starts and ends,
but as the part of the expression, which in my personal opinion is a bug.

Following rewrite of org-capture-expand-embedded-lisp  treats outer parenthesis 
not as a part of the expression:

#+being_src emacs-lisp
(defun org-capture-expand-embedded-elisp (&optional mark)
  "Evaluate embedded elisp %(sexp) and replace with the result.
When optional MARK argument is non-nil, mark Sexp with a text
property (`org-embedded-elisp') for later evaluation.  Only
marked Sexp are evaluated when this argument is nil."
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward "%(" nil t)
      (cond
       ((get-text-property (match-beginning 0) 'org-embedded-elisp)
      (let ((template-start (match-beginning 0)))
        (let* ((sexp (read (current-buffer)))
             (result (org-eval
                    (org-capture--expand-keyword-in-embedded-elisp
                     sexp))))
          (delete-region template-start (1+ (point)))
          (cond
           ((not result) nil)
           ((stringp result) (insert result))
           (t (error
             "Capture template sexp `%s' must evaluate to string or nil"
             sexp))))))
       ((not mark) nil)
       ;; Only mark valid and non-escaped sexp.
       ((org-capture-escaped-%) nil)
       (t
      (let ((end (with-syntax-table emacs-lisp-mode-syntax-table
                 (ignore-errors (scan-sexps (1- (point)) 1)))))
        (when end
          (put-text-property (- (point) 2) end 'org-embedded-elisp t))))))))
#+end_src

With patched function, test1 will now produce correct result, while the test2 
now requires extra pair of parenthesis for the function call:

#+begin_src emacs-lisp
(defun test2 ()
  (with-temp-buffer
    (org-capture-fill-template "%((buffer-name))")))
#+end_src

Is that a change you could accept? It would be useful so we don't have to write 
function wrappers for every variable we would to use
 in a template. I would like to use capture templates to as a lite code 
generator for some readme files and such.

I have attached a patch just because it is easier to see the differences, but I 
can produce a better patch, if you can accept it, or
someone else patch it in, its probably faster.

Attachment: 0001-Let-evaluate-both-variables-and-functions.patch
Description: 0001-Let-evaluate-both-variables-and-functions.patch

Reply via email to