Hi Bastien On Fri, Aug 10, 2012 at 10:53 AM, Bastien <b...@gnu.org> wrote: > Please try the attached patch and let me know if it works.
Thank you for making `org-capture-inside-embedded-elisp-p' much clearer. I was not sure if you really wanted to omit switching to Emacs Lisp Mode although it is useful for example for “%(length ")")”. So I attach a new patch where I restored this part, now cleaner too. Also a small change against your latest patch to not stop at “%” without following “(” and possibly miss a “%(” before. I temporarily emptied “:FEEDSTATUS:” in all my feeds and updated them and also tried some odd artificial examples. All works the same as with my first patch. Can you please review this new patch compared against your latest and apply when appropriate? Michael
From 142625bad45ca07a185d95caa0d810225e389b95 Mon Sep 17 00:00:00 2001 From: Michael Brand <michael.ch.br...@gmail.com> Date: Sat, 11 Aug 2012 17:26:57 +0200 Subject: [PATCH] Add the capture feature sexp to org feed * org-feed.el (org-feed-format-entry): Require `org-capture'. Expand Elisp %(...) templates. (org-feed-default-template): Update docstring. * org-capture.el (org-capture-expand-embedded-elisp): New function. (org-capture-fill-template): Use it. (org-capture-inside-embedded-elisp-p): New function to tell if we are within an Elisp %(...) template. --- lisp/org-capture.el | 40 ++++++++++++++++++++++++++++-------- lisp/org-feed.el | 56 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/lisp/org-capture.el b/lisp/org-capture.el index 84e5ff6..4a11462 100644 --- a/lisp/org-capture.el +++ b/lisp/org-capture.el @@ -1388,15 +1388,7 @@ The template may still contain \"%?\" for cursor positioning." (error (insert (format "%%![Couldn't insert %s: %s]" filename error))))))) ;; %() embedded elisp - (goto-char (point-min)) - (while (re-search-forward "%\\((.+)\\)" nil t) - (unless (org-capture-escaped-%) - (goto-char (match-beginning 0)) - (let ((template-start (point))) - (forward-char 1) - (let ((result (org-eval (read (current-buffer))))) - (delete-region template-start (point)) - (insert result))))) + (org-capture-expand-embedded-elisp) ;; The current time (goto-char (point-min)) @@ -1530,6 +1522,36 @@ The template may still contain \"%?\" for cursor positioning." t) nil)) +(defun org-capture-expand-embedded-elisp () + "Evaluate embedded elisp %(sexp) and replace with the result." + (goto-char (point-min)) + (while (re-search-forward "%(" nil t) + (unless (org-capture-escaped-%) + (goto-char (match-beginning 0)) + (let ((template-start (point))) + (forward-char 1) + (let ((result (org-eval (read (current-buffer))))) + (delete-region template-start (point)) + (insert result)))))) + +(defun org-capture-inside-embedded-elisp-p () + "Return non-nil if point is inside of embedded elisp %(sexp)." + (let ((buf (buffer-string)) (p (point)) beg end) + (with-temp-buffer ; to keep major mode and font-lock in original buffer + (emacs-lisp-mode) ; to deal with for example %(length ")") + (insert buf) + (goto-char p) + ;; `looking-at' and `search-backward' below do not match the "%(" if + ;; point is in its middle + (when (equal (char-before) ?%) + (backward-char)) + (save-match-data + (when (or (looking-at "%(") (search-backward "%(" nil t)) + (setq beg (point)) + (setq end (progn (forward-char) (forward-sexp) (1- (point))))))) + (when (and beg end) + (and (<= p end) (>= p beg))))) + ;;;###autoload (defun org-capture-import-remember-templates () "Set org-capture-templates to be similar to `org-remember-templates'." diff --git a/lisp/org-feed.el b/lisp/org-feed.el index 6901ffa..8b3414b 100644 --- a/lisp/org-feed.el +++ b/lisp/org-feed.el @@ -225,12 +225,14 @@ Any fields from the feed item can be interpolated into the template with %name, for example %title, %description, %pubDate etc. In addition, the following special escapes are valid as well: -%h the title, or the first line of the description -%t the date as a stamp, either from <pubDate> (if present), or - the current date. -%T date and time -%u,%U like %t,%T, but inactive time stamps -%a A link, from <guid> if that is a permalink, else from <link>" +%h The title, or the first line of the description +%t The date as a stamp, either from <pubDate> (if present), or + the current date +%T Date and time +%u,%U Like %t,%T, but inactive time stamps +%a A link, from <guid> if that is a permalink, else from <link> +%(sexp) Evaluate elisp `(sexp)' and replace with the result, the simple + %-escapes above can be used as arguments, e.g. %(capitalize \\\"%h\\\")" :group 'org-feed :type '(string :tag "Template")) @@ -506,9 +508,10 @@ This will find DRAWER and extract the alist." ENTRY is a property list. This function adds a `:formatted-for-org' property and returns the full property list. If that property is already present, nothing changes." + (require 'org-capture) (if formatter (funcall formatter entry) - (let (dlines fmt tmp indent time name + (let (dlines time escape name tmp v-h v-t v-T v-u v-U v-a) (setq dlines (org-split-string (or (plist-get entry :description) "???") "\n") @@ -527,20 +530,35 @@ If that property is already present, nothing changes." "")) (with-temp-buffer (insert template) + + ;; Simple %-escapes + ;; before embedded elisp to support simple %-escapes as + ;; arguments for embedded elisp (goto-char (point-min)) (while (re-search-forward "%\\([a-zA-Z]+\\)" nil t) - (setq name (match-string 1)) - (cond - ((member name '("h" "t" "T" "u" "U" "a")) - (replace-match (symbol-value (intern (concat "v-" name))) t t)) - ((setq tmp (plist-get entry (intern (concat ":" name)))) - (save-excursion - (save-match-data - (beginning-of-line 1) - (when (looking-at (concat "^\\([ \t]*\\)%" name "[ \t]*$")) - (setq tmp (org-feed-make-indented-block - tmp (org-get-indentation)))))) - (replace-match tmp t t)))) + (unless (org-capture-escaped-%) + (setq name (match-string 1) + escape (org-capture-inside-embedded-elisp-p)) + (cond + ((member name '("h" "t" "T" "u" "U" "a")) + (setq tmp (symbol-value (intern (concat "v-" name))))) + ((setq tmp (plist-get entry (intern (concat ":" name)))) + (save-excursion + (save-match-data + (beginning-of-line 1) + (when (looking-at + (concat "^\\([ \t]*\\)%" name "[ \t]*$")) + (setq tmp (org-feed-make-indented-block + tmp (org-get-indentation)))))))) + (when tmp + ;; escape string delimiters `"' when inside %() embedded lisp + (when escape + (setq tmp (replace-regexp-in-string "\"" "\\\\\"" tmp))) + (replace-match tmp t t)))) + + ;; %() embedded elisp + (org-capture-expand-embedded-elisp) + (decode-coding-string (buffer-string) (detect-coding-region (point-min) (point-max) t)))))) -- 1.7.4.2