emacs elisp why won't a variable work here? [duplicate] - emacs

I've seen this:
How to type a dynamic file entry for org capture
but cannot get it to work; I get "Invalid file location: nil". Has something changed in org-mode or in Emacs itself to stop this from working? Otherwise: suggestions for how to debug what has gone wrong?
What I'm really trying to get working is what is described on this page:
http://www.howardism.org/Technical/Emacs/journaling-org.html
The capture template I'm interested in is the "Journal Note" one all the way at the bottom of the page:
(setq org-capture-templates '(
;; ...
("j" "Journal Note"
entry (file (get-journal-file-today))
"* Event: %?\n\n %i\n\n From: %a"
:empty-lines 1)
;; ..
))
Thanks for any assistance.

Figured it out ... it is using a backquote instead of a normal quote for the entire capture template block! I missed this because all of the answers I saw had only a single capture template with a backquote in front of it; I tried doing that but this doesn't work if the template is "one of" ...
So here is a snippet a bit richer than those I found; I hope it helps someone else.
(setq org-capture-templates
`(("t" "TODO" entry (file+datetree "~/Documents/org/tasks.org" "Tasks")
"* TODO [#C] %?\n SCHEDULED: <%<%Y-%m-%d %a>>\n [%<%Y-%m-%d %a>]\n %a")
("T" "Travel" entry (file+datetree+prompt "~/Documents/org/travel.org")
"* %?\n :PROPERTIES:\n :LOCATION:\n :END:\n %t\n %a")
("j" "Journal Note" entry (
file+olp+datetree
,(concat
org-journal-dir
(format-time-string "journal-%m-%d.org")))
"* Event: %?\n %i\n From: %a")
)
)
The keys are the backquote ` at the start of the capture template def block, and the comma , before (concat ... ) on the function being called.

It seems like something has changed between Org-mode 8.2.10 and 9.1.9 specifically in the way Org handles template elements. Whereas in earlier version of Org the second value in the pair (file ...) could be a function that Org would evaluate, now it seems only a string (file path) is valid here.
The fix is to use the backquote list form, and explicitly state that the function needs evaluating using the comma:
(setq org-capture-templates `(
;; ...
("j" "Journal Note"
entry (file ,(get-journal-file-today))
"* Event: %?\n\n %i\n\n From: %a"
:empty-lines 1)
;; ..
))

Related

Customized org-capture-template for Org Capture Extension

I am using the great Org Capture Extension Firefox addon to directly capture my web links into my Emacs documents.
A minimal org capture template is:
(setq org-capture-templates `(
("L" "Protocol Link" entry (file+headline "~/web.org" "Links")
"* [[%:link][%:description]]\n")
;; ... your other templates
))
I use this to bookmark articles, in peculiar a lot of them are on
arxiv.org. The problem is that arxiv title pages contain [] characters, for instance:
[1606.04838] Optimization Methods for Large-Scale Machine Learning
This does not mix well with the [[%:link][%:description]] used in the template to create the org mode link. For instance a capture returns:
** [[https://arxiv.org/abs/1606.04838][[1606.04838] Optimization Methods for Large-Scale Machine Learning]]
and the Org-Mode link is broken because of the brackets in the "[1606.04838]" string.
How to solve this?
The cure is to transform the link [%:description] description into a string that does not contain squared brackets []. For this we can define a function that transforms the [, ] chars into (, ) ones.
(defun transform-square-brackets-to-round-ones(string-to-transform)
"Transforms [ into ( and ] into ), other chars left unchanged."
(concat
(mapcar #'(lambda (c) (if (equal c ?[) ?\( (if (equal c ?]) ?\) c))) string-to-transform))
)
Then we can use this function into the org-capture-template. The %(sexp) syntax is used to evaluate the lisp code into the template:
%(sexp) Evaluate Elisp sexp and replace with the result.
For convenience, %:keyword (see below) placeholders
within the expression will be expanded prior to this.
The sexp must return a string.
The modified org-capture-template is:
(setq org-capture-templates '(
("L" "Protocol Link" entry (file+headline "~/web.org" "Links")
"* [[%:link][%(transform-square-brackets-to-round-ones \"%:description\")]]\n")
;; ... your other templates
))
Then when you click on the Firefox Org-Capture button the template is correctly expended to
** (1606.04838) Optimization Methods for Large-Scale Machine Learning
with a well formed Org-Mode link (note that the [1606.04838] was turned into (1606.04838))

How to add tags completion to org mode capture?

I use org mode's capture functionality to make all my todo's. It is clean and practical and let me add a consistent content to all my todo's, including a prompt for heading, a prompt for tags and an automatic insertion of created date. Here is my code:
(setq org-capture-templates '((
"t" ; key
"Todo" ; description
entry ; type
(file+headline "C:/.../org/notes.org" "tasks") ; target
"* TODO [#B] %^{Todo} :%^{Tags}: \n:PROPERTIES:\n:Created: %U\n:END:\n\n%?" ; template
:prepend t ; properties
:empty-lines 1 ; properties
:created t ; properties
)))
However, my prompt for tags forces me to enter tags from memory. How could I add tags from the tags list set by the following code:
(setq org-tag-alist `(
("OFFICE" . ?o)
("HOME" . ?h)
("ERRAND" . ?e) ))
When my point is in the heading of an already created task, this list pops up when I hit C-c C-c and let me chose the tags by their short cut single letters "o", "h" or "e".
So my question is: is it possible to include this pop-up list of tags inside the code for my capture?
The built in solution is to use %^g. From the help for org-capture-templates:
%^g Prompt for tags, with completion on tags in target file.
%^G Prompt for tags, with completion on all tags in all agenda files.
You can also do this "by hand" by calling some function that adds the tags. Adding tags is generally done with org-set-tags (this is what C-c C-c is doing). So, all we have to do is call that in our template with the %(func) syntax:
(setq org-capture-templates '((
"t" ; key
"Todo" ; description
entry ; type
(file+headline "C:/.../org/notes.org" "tasks") ; target
"* TODO [#B] %^{Todo} %(org-set-tags) \n:PROPERTIES:\n:Created: %U\n:END:\n\n%?" ; template
:prepend t ; properties
:empty-lines 1 ; properties
:created t ; properties
)))
If you have a specific list of tags you want to select from (say org-tag-alist) you can use completing-read to select from it:
(completing-read "Tag: " (mapcar #'first org-tag-persistent-alist) nil t)

Log time spent on emacs org-mode capture items

I have a capture template set up to file journal entries in an org file.
(setq org-capture-templates
'(("j" "Journal" entry (file+datetree "/home/emil/org/journal_.org")
(file "/home/emil/org/journal-template.org") :prepend :clock-in))
I want to clock out and output the time elapsed on the clock started with :clock-in when the capture is filed, but I don't know how to do this. Can anyone give me some ideas?
I think you got the template slightly wrong.
Here's how I have it:
(setq org-capture-templates
`(("t" "todo" entry
(file+headline (concat org.d "gtd.org") "Tasks")
"* TODO %^{Brief Description} %^g \nAdded: %U %i\n %?\n"
:clock-in t :clock-resume t)))
So that's :clock-in t, not just plain :clock-in.

Add CREATED date property to TODOs in org-mode

I read the org-mode manual but couldn't find an easy way to add a CREATED field to newly created TODOs. In combination with org-log-done one could then compute the time it took to close a particular TODO. This is especially useful when using archive files.
Example:
* TODO Do something
CREATED: [2012-09-02 Sun 23:02]
* DONE Do something else
CREATED: [2012-09-02 Sun 20:02]
CLOSED: [2012-09-02 Sun 22:02]
I would expect the CREATED field to be added to new tasks (tasks which don't have that field) whenever the file is saved.
Any suggestions on how to achieve this? Using something like Git is not a solution for me to track the creations of TODOS.
I use org-expiry to implement that functionality, which is in the contrib directory of org.
The base configuration I use is:
;; Allow automatically handing of created/expired meta data.
(require 'org-expiry)
;; Configure it a bit to my liking
(setq
org-expiry-created-property-name "CREATED" ; Name of property when an item is created
org-expiry-inactive-timestamps t ; Don't have everything in the agenda view
)
(defun mrb/insert-created-timestamp()
"Insert a CREATED property using org-expiry.el for TODO entries"
(org-expiry-insert-created)
(org-back-to-heading)
(org-end-of-line)
(insert " ")
)
;; Whenever a TODO entry is created, I want a timestamp
;; Advice org-insert-todo-heading to insert a created timestamp using org-expiry
(defadvice org-insert-todo-heading (after mrb/created-timestamp-advice activate)
"Insert a CREATED property using org-expiry.el for TODO entries"
(mrb/insert-created-timestamp)
)
;; Make it active
(ad-activate 'org-insert-todo-heading)
If you are using capture it does not automatically work and needs a little glue. I have posted the complete config here: https://gist.github.com/4037694
A more lightweight solution would be to add ! flag to the TODO state:
(setq org-todo-keywords '((sequence "TODO(!)" "DONE")))
Then:
* TODO get of your ass
- State "TODO" from [2016-06-03 to. 10:35]
It isn't very pretty though.
Ref: http://orgmode.org/org.html#Tracking-TODO-state-changes
You don't need to modify functions with 'defadvice' to run expiry code on capture.
You should use hook:
(add-hook 'org-capture-before-finalize-hook
(lambda()
(save-excursion
(org-back-to-heading)
(org-expiry-insert-created))))
Same for 'org-insert-todo-heading'. There is a hook:
(add-hook 'org-insert-todo-heading-hook
(lambda()
(save-excursion
(org-back-to-heading)
(org-expiry-insert-created))))
Org provides a hook org-after-todo-state-change-hook which you can use here:
org-after-todo-state-change-hook is a variable defined in ‘org.el’.
Documentation:
Hook which is run after the state of a TODO item was changed.
The new state (a string with a TODO keyword, or nil) is available in the
Lisp variable ‘org-state’.
Use it as follows:
(require 'org-expiry)
(add-hook 'org-after-todo-state-change-hook
(lambda ()
(when (string= org-state "TODO")
(save-excursion
(org-back-to-heading)
(org-expiry-insert-created)))))
org-expiry is part of org-contrib, which is included in the org-plus-contrib package on the org ELPA.
Here's a buried treasure:
(setq org-treat-insert-todo-heading-as-state-change t)
I found it here, in response to someone saying they wanted an org-insert-todo-heading-hook.
Just tried it out and, true to form, when you org-insert-todo-heading, it counts as a state change, so ex: #+TODO: TODO(t!) | ... will add a log.
If you create all your TODOs with org-capture the following capture template does the trick:
(setq org-capture-templates
'(
("t" "TODO Task" entry (file+headline "~/inbox.org" "Tasks")
"* TODO %?\nCREATED: %u\nSRC: %a\n%i\n")
))
The result will look something like this:
* Tasks
** TODO Dummy task
CREATED: [2015-05-08 Fri]
SRC: [[file:~/path/to/file/where/you/created/the/task.org::*heading"][heading]]
Here is a lightweight solution that does not require an external package. I got it from the answer by #MarcinAntczak, the comments by #Clément, and this similar thread. It works with org-capture and with M-S-RET. Put this in your Emacs initialization file (e.g. ~/.emacs):
(defun insert-created-date(&rest ignore)
(insert (format-time-string
(concat "\nCREATED: "
(cdr org-time-stamp-formats))
))
(org-back-to-heading) ; in org-capture, this folds the entry; when inserting a heading, this moves point back to the heading line
(move-end-of-line()) ; when inserting a heading, this moves point to the end of the line
)
; add to the org-capture hook
(add-hook 'org-capture-before-finalize-hook
#'insert-created-date
)
; hook it to adding headings with M-S-RET
; do not add this to org-insert-heading-hook, otherwise this also works in non-TODO items
; and Org-mode has no org-insert-todo-heading-hook
(advice-add 'org-insert-todo-heading :after #'insert-created-date)
I did not add this function to state changes (e.g., from plain heading to TODO) because it would need to be in a properties drawer and I prefer to not have those extra lines. If you prefer to have it in properties, use the function defined in see this thread.
You can add a time stamp at creation time with zero config, but it won't be labeled CREATED. Rather than manually typing TODO, use C-c C-t. It will then be logged as "state changed to TODO from """ and time stamped.

Interactively enter headline under which to place an entry using capture

Using capture templates like the one below, I can add entries to different headlines in a file. How can I manually enter a headline during capture, instead of setting up each headline to a key in the .emacs file like I am now doing?
(setq org-capture-templates
'(
("l" "Log" entry
(file+headline "c:/Org/log.org" "Log")
"\n\n** %?\n<%<%Y-%m-%d %a %T>>"
:empty-lines 1))
It looks like, in newer versions of org at least, that custom functions can be used in capture templates to do this.
Instead of:
entry
(file+headline "~/Work/work.org" "Refile")
You can use:
entry
(file+function "~/Work/work.org" function-finding-location)
Where 'function-finding-location' is a custom function you have written yourself, which could easily prompt you for a headline.
Or, you can go even farther, and define a custom function which will prompt for both file name and headline name (or anything else you can dream up):
entry
(function function-finding-location)
I don't really know enough elisp to write these functions myself, but this looks like the place to start. It'd be nice if someone else could offer up some code. The relevant documentation is here:
http://orgmode.org/manual/Template-elements.html
I wrote a function to be used with file+function which will prompt for a location on capture.
It uses the internal prompting function of org-refile so we get completions of headings in the prompt (with maxlevels overridden to 9). When the user enters an unknown heading, it creates it at the end of the file.
(defun org-ask-location ()
(let* ((org-refile-targets '((nil :maxlevel . 9)))
(hd (condition-case nil
(car (org-refile-get-location nil nil t t))
(error (car org-refile-history)))))
(goto-char (point-min))
(outline-next-heading)
(if (re-search-forward
(format org-complex-heading-regexp-format (regexp-quote hd))
nil t)
(goto-char (point-at-bol))
(goto-char (point-max))
(or (bolp) (insert "\n"))
(insert "* " hd "\n")))
(end-of-line))
In your case, you use it like this:
(setq org-capture-templates
'(("l" "Log" entry
(file+function "c:/Org/log.org" org-ask-location)
"\n\n** %?\n<%<%Y-%m-%d %a %T>>"
:empty-lines 1))
I don't believe you can have it prompt for the headline on capture. You can however refile from within the capture window which should result in the desired behaviour.
I would define a catch-all target headline/file so that if you forget you will always collect them in the same location and then just have to refile them once created. If you also set a category/tag on this headline you will be able to easily see the misfiled capture entry and refile it as desired. (Example below)
Then instead of finishing with C-c C-c choose to refile with C-c C-w and you will be asked to select the headline you want to send the new entry to.
The capture template I use for this catch all is as follows (adapted from Bernt Hansen's capture settings)
("i"
"Incidents"
entry
(file+headline "~/Work/work.org" "Refile")
"* TODO %^{Ticket} - %^{User}\nSCHEDULED: %^t DEADLINE: %^t\n:PROPERTIES:
\n:DATE: %^U\n:END:\n%^{MANAGER}p%^{HOSTNAME}p%^{LOCATION}p%^{TEL}p\n%c"
:empty-lines 1 :clock-in t :clock-resume t)
(Line breaks are added to avoid scrolling when reading here)
The heading is configured as follows
* Refile :refile:
:PROPERTIES:
:CATEGORY: Unsorted
:END:
With this I end up with all non-refiled tasks showing up as
Unsorted: Deadline: TODO <Headline> :refile::
I currently tend to use tags as reference if I'm waiting for coworkers/managers to deal with the ticket, or to remind me to speak to them about it when I see them so the tag at the end stands out clearly, as does Unsorted if I'm trying to remember what the issue is (since I simply have a case number and user name showing, details within the entry).
while capturing a note, after finishing writeup press C-u C-c C-w to refile under desired new headline.
you also need to set this variable
(setq org-refile-allow-creating-parent-nodes (quote confirm))
you can set it to t instead of confirm. But I like it be confirm because I dont often refile to new targets