Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

org-mode capture with sexp

Tags:

emacs

org-mode

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 first %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.

like image 729
pmr Avatar asked Jul 13 '11 15:07

pmr


3 Answers

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.

like image 105
pmr Avatar answered Nov 09 '22 04:11

pmr


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)

like image 6
Jonathan Leech-Pepin Avatar answered Nov 09 '22 02:11

Jonathan Leech-Pepin


@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.

like image 4
studgeek Avatar answered Nov 09 '22 04:11

studgeek