2

I have a variety of org easy templates. I have a new file template which includes a #+DATE header that I'd like to populate with the current date [at the time the template is called].

The concatenated string I'd like to insert could be printed in the minibuffer using:

(concat "#+DATE: " (format-time-string "%m/%d/%Y"))

I try to implement this in my easy template, however, when I include the following in my config file, emacs will not compile the code:

  (eval-after-load 'org
    '(progn
       (add-to-list 'org-structure-template-alist '("n" (concat "#+DATE: " (format-time-string "%m/%d/%Y"))))))

I'm trying to get an error message (running emacs with --debut-init), but I'm not seeing anything. I ran across this SX thread where the OP describes a problem using concat in org-capture-templates. The only reply is to add a backquote (,) before the concat, so I try this:

  (eval-after-load 'org
    '(progn
       (add-to-list 'org-structure-template-alist '("n" ,(concat "#+DATE: " (format-time-string "%m/%d/%Y"))))))

This is still being ignored, and I'm not seeing feedback from the debugger. Any ideas?

1) How should I fix this?

2) What's the best way to go about tracing this type of problem myself in the future?

Drew
  • 75,699
  • 9
  • 109
  • 225
ch-pub
  • 220
  • 1
  • 10

1 Answers1

2

As @Drew mentioned in the comments, you can accomplish this, almost, with quasi-quoting. The syntax is a little confusing. The variable org-structure-template-alist is initialized as an alist:

'(("s" "#+BEGIN_SRC ?\n\n#+END_SRC")
  ("e" "#+BEGIN_EXAMPLE\n?\n#+END_EXAMPLE")
  ("q" "#+BEGIN_QUOTE\n?\n#+END_QUOTE")
  ...
     )

You want to insert an element that includes the concat form, and you need to evaluate that form and leave the rest of the alist 'as-is'. You can do this by switching from a straight quote to a back-quote, then using the , to indicate that the concat needs to be evaluated:

`(("n" ,(concat "#+DATE: "
          (format-time-string "%m/%d/%Y")))
  ("s" "#+BEGIN_SRC ?\n\n#+END_SRC")
  ("e" "#+BEGIN_EXAMPLE\n?\n#+END_EXAMPLE")
  ("q" "#+BEGIN_QUOTE\n?\n#+END_QUOTE")
  ...
     )

Note that you can't back-quote just the template you add (i.e., the ("n" ...) part). If you leave the original quote symbol, you can't selectively backquote the parts nested inside it. You need to backquote the entire list, as I've done - change the initial ' to a `. Once you do that, you can use the comma to get the concat form evaluated.

You can't accomplish this with add-to-list, since you need to change the entire list, not just add something to it. It will be easier to modify the variable via M-x customize-variable org-structure-template-alist. You may need to change the state to "Show saved Lisp expresssion", as you'll need to see the actual list to change the leading quote to a backquote.

BEWARE! There is a catch. This form gets evaluated once, when your initialization runs. That is, when you start Emacs. That will be fine if you start Emacs at 9 AM and close it at 5 PM. But should you have a session that runs longer than one day (i.e., lasts past midnight), your easy template will continue to insert the day at the time you started Emacs, not the current day. If that will be an issue for you, you'll need to find a more robust solution. Or maybe just redefine the variable at the beginning of each day with a timer of some sort.

Tyler
  • 21,719
  • 1
  • 52
  • 92
  • Thanks for the explanation! Also interested in the **catch** you mention, but I /will/ open that as another question. – ch-pub Aug 10 '18 at 14:19
  • @ClarkHenry So, did you investigate how to deal with the **catch**? (I didn't find the other question you mention) As an alternative, is there another way to have the `#+DATE` field receive the date **at the calling time** of this easy template? – Giuseppe Oct 12 '19 at 20:03