浏览代码

org-macro: Expand macros only within narrowed part of buffer

* lisp/org-macro.el (org-macro-replace-all): Expand macros only within
  narrowed part of buffer.
* testing/lisp/test-org-macro.el (test-org/macro-replace-all): Update
  test.

Expanding macros outside in the whole buffer could make sense, e.g.,
if a macro expands to some Babel code, which, in turn, is evaluated
prior to export.  However, by principle of least surprise, it is
better to limit expansion to current accessible part of the buffer.
Nicolas Goaziou 7 年之前
父节点
当前提交
82db669de6
共有 2 个文件被更改,包括 51 次插入57 次删除
  1. 48 54
      lisp/org-macro.el
  2. 3 3
      testing/lisp/test-org-macro.el

+ 48 - 54
lisp/org-macro.el

@@ -49,11 +49,7 @@
 
 (declare-function org-element-at-point "org-element" ())
 (declare-function org-element-context "org-element" (&optional element))
-(declare-function org-element-map "org-element"
-		  (data types fun &optional info first-match no-recursion
-			with-affiliated))
-(declare-function org-element-parse-buffer "org-element"
-		  (&optional granularity visible-only))
+(declare-function org-element-macro-parser "org-element" ())
 (declare-function org-element-property "org-element" (property element))
 (declare-function org-element-type "org-element" (element))
 (declare-function org-file-contents "org" (file &optional noerror))
@@ -189,55 +185,53 @@ found in the buffer with no definition in TEMPLATES.
 
 Optional argument KEYWORDS, when non-nil is a list of keywords,
 as strings, where macro expansion is allowed."
-  (org-with-wide-buffer
-   (goto-char (point-min))
-   (let ((properties-regexp
-	  (format "\\`EXPORT_%s\\+?\\'" (regexp-opt keywords)))
-	 record)
-     (while (re-search-forward "{{{[-A-Za-z0-9_]" nil t)
-       (let* ((datum (save-match-data (org-element-context)))
-	      (type (org-element-type datum))
-	      (macro
-	       (cond
-		((eq type 'macro) datum)
-		;; In parsed keywords and associated node properties,
-		;; force macro recognition.
-		((or (and (eq type 'keyword)
-			  (member (org-element-property :key datum) keywords))
-		     (and (eq type 'node-property)
-			  (string-match-p
-			   properties-regexp
-			   (org-element-property :key datum))))
-		 (save-restriction
-		   (narrow-to-region (match-beginning 0) (line-end-position))
-		   (org-element-map (org-element-parse-buffer) 'macro
-		     #'identity nil t))))))
-	 (when macro
-	   (let* ((value (org-macro-expand macro templates))
-		  (begin (org-element-property :begin macro))
-		  (signature (list begin
-				   macro
-				   (org-element-property :args macro))))
-	     ;; Avoid circular dependencies by checking if the same
-	     ;; macro with the same arguments is expanded at the same
-	     ;; position twice.
-	     (cond ((member signature record)
-		    (error "Circular macro expansion: %s"
-			   (org-element-property :key macro)))
-		   (value
-		    (push signature record)
-		    (delete-region
-		     begin
-		     ;; Preserve white spaces after the macro.
-		     (progn (goto-char (org-element-property :end macro))
-			    (skip-chars-backward " \t")
-			    (point)))
-		    ;; Leave point before replacement in case of
-		    ;; recursive expansions.
-		    (save-excursion (insert value)))
-		   (finalize
-		    (error "Undefined Org macro: %s; aborting"
-			   (org-element-property :key macro)))))))))))
+  (save-excursion
+    (goto-char (point-min))
+    (let ((properties-regexp
+	   (format "\\`EXPORT_%s\\+?\\'" (regexp-opt keywords)))
+	  record)
+      (while (re-search-forward "{{{[-A-Za-z0-9_]" nil t)
+	(let* ((datum (save-match-data (org-element-context)))
+	       (type (org-element-type datum))
+	       (macro
+		(cond
+		 ((eq type 'macro) datum)
+		 ;; In parsed keywords and associated node properties,
+		 ;; force macro recognition.
+		 ((or (and (eq type 'keyword)
+			   (member (org-element-property :key datum) keywords))
+		      (and (eq type 'node-property)
+			   (string-match-p properties-regexp
+					   (org-element-property :key datum))))
+		  (save-excursion
+		    (goto-char (match-beginning 0))
+		    (org-element-macro-parser))))))
+	  (when macro
+	    (let* ((value (org-macro-expand macro templates))
+		   (begin (org-element-property :begin macro))
+		   (signature (list begin
+				    macro
+				    (org-element-property :args macro))))
+	      ;; Avoid circular dependencies by checking if the same
+	      ;; macro with the same arguments is expanded at the same
+	      ;; position twice.
+	      (cond ((member signature record)
+		     (error "Circular macro expansion: %s"
+			    (org-element-property :key macro)))
+		    (value
+		     (push signature record)
+		     (delete-region
+		      begin
+		      ;; Preserve white spaces after the macro.
+		      (progn (goto-char (org-element-property :end macro))
+			     (skip-chars-backward " \t")
+			     (point)))
+		     ;; Leave point before replacement in case of
+		     ;; recursive expansions.
+		     (save-excursion (insert value)))
+		    (finalize
+		     (error "Undefined Org macro: %s; aborting"
+			    (org-element-property :key macro)))))))))))
 
 (defun org-macro-escape-arguments (&rest args)
   "Build macro's arguments string from ARGS.

+ 3 - 3
testing/lisp/test-org-macro.el

@@ -108,10 +108,10 @@
        "* H1\n:PROPERTIES:\n:A: 1\n:END:\n* H2\n{{{property(A,*???)}}}<point>"
      (org-macro-initialize-templates)
      (org-macro-replace-all org-macro-templates)))
-  ;; Macro expansion ignores narrowing.
+  ;; Macro expansion preserves narrowing.
   (should
-   (string-match
-    "expansion"
+   (string-match-p
+    "{{{macro}}}"
     (org-test-with-temp-text
 	"#+MACRO: macro expansion\n{{{macro}}}\n<point>Contents"
       (narrow-to-region (point) (point-max))