org-mode capture with sexp
I'm trying to get create a capture template that converts an URL to an org-mode link with the <title>
as the link name.
My conversion function looks like this:
(defun get-page-title (url)
"Get title of web page, whose url can be found in the current line"
;; Get title of web page, with the help of functions in url.el
(with-current-buffer (url-retrieve-synchronously url)
;; find title by grep the html code
(goto-char 0)
(re-search-forward "<title>\\([^<]*\\)</title>" nil t 1)
(setq web_title_str (match-string 1))
;; find charset by grep the html code
(goto-char 0)
;; find the charset, assume utf-8 otherwise
(if (re-search-forward "charset=\\([-0-9a-zA-Z]*\\)" nil t 1)
(setq coding_charset (downcase (match-string 1)))
(setq coding_charset "utf-8")
;; decode the string of title.
(setq web_title_str (decode-coding-string web_title_str (intern
coding_charset)))
)
(concat "[[" url "][" web_title_str "]]")
))
When called from normal emacs lisp code it returns the correct result. But when used in this org-capture-template
it only returns bad url
.
setq org-capture-templates
(quote
(("l" "Link" entry (file+headline "" "Links")
"* \"%c\" %(get-page-title \"%c\")"))))
Is the order of expansion different? Do I need to escape the string differently? Magic?
The fi开发者_JS百科rst %c
is only their to debug the string and indeed is getting printed as "url".
Please don't even bother pointing out that parsing XML with regexp is the wrong approach. Cthulhu is already haunting me and this isn't going to make it worse.
The problem is the order of expansion of template parameters. The simple %
templates are expanded after the sexp has been evaluated. The original error message still contains a template and thus is expanded into the contents of the clipboard and thus the error message contains not the string that was originally passed to get-page-title
.
The solution is to access the kill ring from within the sexp:
%(get-page-title (current-kill 0))
EDIT This behavior is now documented in org-mode.
Wouldn't the solution be to use org-protocol.el? http://orgmode.org/worg/org-contrib/org-protocol.html
I just tested it with the following template (adding a sub-heading for your desired title as headline).
Template:
("t"
"Testing Template"
entry
(file+headline "~/org/capture.org" "Testing")
"* %^{Title}\n** %:description\n\n Source: %u, %c\n\n%i"
:empty-lines 1)
Then using a browser-based keybind (in my case with Opera, although examples for Firefox, Uzbl, Acrobat and Conkeror are provided as well) I was able to capture the following:
** Testing for StackExchange
*** org-protocol.el - Intercept calls from emacsclient to trigger custom actions
Source: [2011-08-05 Fri], [[http://orgmode.org/worg/org-contrib/org-protocol.html]
[org-protocol.el - Intercept calls from emacsclient to trigger custom actions]]
org-protocol intercepts calls from emacsclient to trigger custom actions
without external dependencies.
(I broke the org-link simply to keep the scrolling to a minimum, it was not on two lines originally)
@aboabo shared an undocumented variable in https://stackoverflow.com/a/21080770/255961 that provides a more general solution to the question's topic of how to use sexp with keyword values in a template (beyond kill ring). The variable org-store-link-plist
stores all the information being passed to the capture. So you can access its values directly from a function like this:
(defun url()
(plist-get org-store-link-plist :url))
("w" "capture" entry (file "~/refile.org")
"* [[%:link][%:description]] :NOTE:\n%(url)%U\n"
:immediate-finish t)
PS, According to the manual page (quote below) it sounds to me like your approach in teh question should work also. But I agree what you describe is what seems to be actually happening - it seems like a bug relative to the manual.
%(sexp) Evaluate Elisp sexp and replace with the result. For convenience, %:keyword (see below) placeholders within the expression will be expanded prior to this.
精彩评论