summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2017-12-16 16:07:09 +0100
committerNicolas Goaziou <mail@nicolasgoaziou.fr>2017-12-17 09:40:56 +0100
commit3ac619c8ac9934a2a1368f3de8ffad951f900067 (patch)
tree0a2c7867d24041d21ae56377469cc19e201f467f
parent3f2968c6500cee53898c79b1e0f37a46d730a08e (diff)
downloadorg-mode-3ac619c8ac9934a2a1368f3de8ffad951f900067.tar.gz
org-macro: Placeholders in (eval ...) macros are always strings
* lisp/org-macro.el (org-macro-initialize-templates): Update templates. (org-macro-expand): Ensure placeholders in "eval" macros are strings. * testing/lisp/test-org-macro.el (test-org/macro-replace-all): Update tests.
-rw-r--r--etc/ORG-NEWS23
-rw-r--r--lisp/org-macro.el46
-rw-r--r--testing/lisp/test-org-macro.el24
3 files changed, 61 insertions, 32 deletions
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index cbe3651..87e147f 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -58,6 +58,29 @@ With the new template expansion mechanism (see
[[*~org-insert-structure-template~]]), the variable changed its data type.
See docstring for details.
+*** Placeholders in =(eval ...)= macros are always strings
+
+Within =(eval ...)= macros, =$1=-like placeholders are always replaced
+with a string. As a consequence, they must not be enclosed within
+quotes. As an illustration, consider the following, now valid,
+examples:
+
+#+begin_example
+ ,#+macro: join (eval (concat $1 $2))
+ ,#+macro: sum (eval (+ (string-to-number $1) (string-to-number $2)))
+
+ {{{join(a,b)}}} => ab
+ {{{sum(1,2)}}} => 3
+#+end_example
+
+However, there is no change in non-eval macros:
+
+#+begin_example
+ ,#+macro: disp argument: $1
+
+ {{{disp(text)}}} => argument: text
+#+end_example
+
*** =align= STARTUP value no longer narrow table columns
Columns narrowing (or shrinking) is now dynamic. See [[*Dynamically
diff --git a/lisp/org-macro.el b/lisp/org-macro.el
index 6c4fc5b..03da23a 100644
--- a/lisp/org-macro.el
+++ b/lisp/org-macro.el
@@ -151,20 +151,20 @@ function installs the following ones: \"property\",
(if (and (consp date)
(not (cdr date))
(eq (org-element-type (car date)) 'timestamp))
- (format "(eval (if (org-string-nw-p \"$1\") %s %S))"
- (format "(org-timestamp-format '%S \"$1\")"
+ (format "(eval (if (org-string-nw-p $1) %s %S))"
+ (format "(org-timestamp-format '%S $1)"
(org-element-copy (car date)))
value)
value)))
(cons "email" (org-macro--find-keyword-value "EMAIL"))
- (cons "keyword" "(eval (org-macro--find-keyword-value \"$1\"))")
+ (cons "keyword" "(eval (org-macro--find-keyword-value $1))")
(cons "results" "$1")
(cons "title" (org-macro--find-keyword-value "TITLE"))))
;; Install "property", "time" macros.
(mapc update-templates
(list (cons "property"
"(eval (save-excursion
- (let ((l \"$2\"))
+ (let ((l $2))
(when (org-string-nw-p l)
(condition-case _
(let ((org-link-search-must-match-exact-headline t))
@@ -172,8 +172,8 @@ function installs the following ones: \"property\",
(error
(error \"Macro property failed: cannot find location %s\"
l)))))
- (org-entry-get nil \"$1\" 'selective)))")
- (cons "time" "(eval (format-time-string \"$1\"))")))
+ (org-entry-get nil $1 'selective)))")
+ (cons "time" "(eval (format-time-string $1))")))
;; Install "input-file", "modification-time" macros.
(let ((visited-file (buffer-file-name (buffer-base-buffer))))
(when (and visited-file (file-exists-p visited-file))
@@ -181,8 +181,8 @@ function installs the following ones: \"property\",
(list (cons "input-file" (file-name-nondirectory visited-file))
(cons "modification-time"
(format "(eval
-\(format-time-string \"$1\"
- (or (and (org-string-nw-p \"$2\")
+\(format-time-string $1
+ (or (and (org-string-nw-p $2)
(org-macro--vc-modified-time %s))
'%s)))"
(prin1-to-string visited-file)
@@ -191,7 +191,7 @@ function installs the following ones: \"property\",
;; Initialize and install "n" macro.
(org-macro--counter-initialize)
(funcall update-templates
- (cons "n" "(eval (org-macro--counter-increment \"$1\" \"$2\"))"))
+ (cons "n" "(eval (org-macro--counter-increment $1 $2))"))
(setq org-macro-templates templates)))
(defun org-macro-expand (macro templates)
@@ -204,18 +204,22 @@ default value. Return nil if no template was found."
;; Macro names are case-insensitive.
(cdr (assoc-string (org-element-property :key macro) templates t))))
(when template
- (let ((value (replace-regexp-in-string
- "\\$[0-9]+"
- (lambda (arg)
- (or (nth (1- (string-to-number (substring arg 1)))
- (org-element-property :args macro))
- ;; No argument: remove place-holder.
- ""))
- template nil 'literal)))
- ;; VALUE starts with "(eval": it is a s-exp, `eval' it.
- (when (string-match "\\`(eval\\>" value)
- (setq value (eval (read value))))
- ;; Return string.
+ (let* ((eval? (string-match-p "\\`(eval\\>" template))
+ (value
+ (replace-regexp-in-string
+ "\\$[0-9]+"
+ (lambda (m)
+ (let ((arg (or (nth (1- (string-to-number (substring m 1)))
+ (org-element-property :args macro))
+ ;; No argument: remove place-holder.
+ "")))
+ ;; `eval' implies arguments are strings.
+ (if eval? (format "%S" arg) arg)))
+ template nil 'literal)))
+ (when eval?
+ (setq value (eval (condition-case nil (read value)
+ (error (debug))))))
+ ;; Force return value to be a string.
(format "%s" (or value ""))))))
(defun org-macro-replace-all (templates &optional keywords)
diff --git a/testing/lisp/test-org-macro.el b/testing/lisp/test-org-macro.el
index ff542f8..3705720 100644
--- a/testing/lisp/test-org-macro.el
+++ b/testing/lisp/test-org-macro.el
@@ -29,9 +29,9 @@
(equal
"#+MACRO: A B\n1 B 3"
(org-test-with-temp-text "#+MACRO: A B\n1 {{{A}}} 3"
- (progn (org-macro-initialize-templates)
- (org-macro-replace-all org-macro-templates)
- (buffer-string)))))
+ (org-macro-initialize-templates)
+ (org-macro-replace-all org-macro-templates)
+ (buffer-string))))
;; Macro with arguments.
(should
(equal
@@ -43,20 +43,22 @@
;; Macro with "eval".
(should
(equal
- "#+MACRO: add (eval (+ $1 $2))\n3"
- (org-test-with-temp-text "#+MACRO: add (eval (+ $1 $2))\n{{{add(1,2)}}}"
- (progn (org-macro-initialize-templates)
- (org-macro-replace-all org-macro-templates)
- (buffer-string)))))
+ "3"
+ (org-test-with-temp-text
+ "#+MACRO: add (eval (+ (string-to-number $1) (string-to-number $2)))
+<point>{{{add(1,2)}}}"
+ (org-macro-initialize-templates)
+ (org-macro-replace-all org-macro-templates)
+ (buffer-substring-no-properties (point) (line-end-position)))))
;; Nested macros.
(should
(equal
"#+MACRO: in inner\n#+MACRO: out {{{in}}} outer\ninner outer"
(org-test-with-temp-text
"#+MACRO: in inner\n#+MACRO: out {{{in}}} outer\n{{{out}}}"
- (progn (org-macro-initialize-templates)
- (org-macro-replace-all org-macro-templates)
- (buffer-string)))))
+ (org-macro-initialize-templates)
+ (org-macro-replace-all org-macro-templates)
+ (buffer-string))))
;; Error out when macro expansion is circular.
(should-error
(org-test-with-temp-text