From 757d415af6247ea85f260daaeeb9f143f41e6103 Mon Sep 17 00:00:00 2001 From: Bastien Guerry Date: Fri, 10 Aug 2012 10:52:13 +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 | 34 ++++++++++++++++++++++--------- lisp/org-feed.el | 56 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 62 insertions(+), 28 deletions(-) diff --git a/lisp/org-capture.el b/lisp/org-capture.el index 05e3a0c..7119c2d 100644 --- a/lisp/org-capture.el +++ b/lisp/org-capture.el @@ -1371,15 +1371,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)) @@ -1513,6 +1505,30 @@ 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 (beg end) + (save-excursion + (save-match-data + (when (or (looking-at "%(") + (and (search-backward "%" nil t) (looking-at "%("))) + (setq beg (point)) + (setq end (progn (forward-char) (forward-sexp) (1- (point))))))) + (when (and beg end) + (and (<= (point) end) (>= (point) 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 (if present), or - the current date. -%T date and time -%u,%U like %t,%T, but inactive time stamps -%a A link, from if that is a permalink, else from " +%h The title, or the first line of the description +%t The date as a stamp, either from (if present), or + the current date +%T Date and time +%u,%U Like %t,%T, but inactive time stamps +%a A link, from if that is a permalink, else from +%(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.10.2