Procházet zdrojové kódy

macro: Implement argument extracting and escaping functions

* lisp/org-macro.el (org-macro-escape-arguments,
  org-macro-extract-arguments): New functions.

* lisp/org-element.el (org-element-macro-parser): Use new function.

* testing/lisp/test-org-macro.el (test-org-macro/escape-arguments,
  test-org-macro/extract-arguments): New tests.
Nicolas Goaziou před 10 roky
rodič
revize
ec0706ea40
3 změnil soubory, kde provedl 70 přidání a 12 odebrání
  1. 1 12
      lisp/org-element.el
  2. 45 0
      lisp/org-macro.el
  3. 24 0
      testing/lisp/test-org-macro.el

+ 1 - 12
lisp/org-element.el

@@ -3091,18 +3091,7 @@ Assume point is at the macro."
 			       (skip-chars-forward " \t")))
 	    (end (point))
 	    (args (let ((args (org-match-string-no-properties 3)))
-		    (when args
-		      ;; Do not use `org-split-string' since empty
-		      ;; strings are meaningful here.
-		      (split-string
-		       (replace-regexp-in-string
-			"\\(\\\\*\\)\\(,\\)"
-			(lambda (str)
-			  (let ((len (length (match-string 1 str))))
-			    (concat (make-string (/ len 2) ?\\)
-				    (if (zerop (mod len 2)) "\000" ","))))
-			args nil t)
-		       "\000")))))
+		    (and args (org-macro-extract-arguments args)))))
 	(list 'macro
 	      (list :key key
 		    :value value

+ 45 - 0
lisp/org-macro.el

@@ -30,6 +30,10 @@
 ;; `org-macro-initialize-templates', which recursively calls
 ;; `org-macro--collect-macros' in order to read setup files.
 
+;; Argument in macros are separated with commas. Proper escaping rules
+;; are implemented in `org-macro-escape-arguments' and arguments can
+;; be extracted from a string with `org-macro-extract-arguments'.
+
 ;; Along with macros defined through #+MACRO: keyword, default
 ;; templates include the following hard-coded macros:
 ;; {{{time(format-string)}}}, {{{property(node-property)}}},
@@ -195,6 +199,47 @@ found in the buffer with no definition in TEMPLATES."
 		       (error "Undefined Org macro: %s; aborting."
 			      (org-element-property :key object))))))))))))
 
+(defun org-macro-escape-arguments (&rest args)
+  "Build macro's arguments string from ARGS.
+ARGS are strings.  Return value is a string with arguments
+properly escaped and separated with commas.  This is the opposite
+of `org-macro-extract-arguments'."
+  (let ((s ""))
+    (dolist (arg (reverse args) (substring s 1))
+      (setq s
+	    (concat
+	     ","
+	     (replace-regexp-in-string
+	      "\\(\\\\*\\),"
+	      (lambda (m)
+		(concat (make-string (1+ (* 2 (length (match-string 1 m)))) ?\\)
+			","))
+	      ;; If a non-terminal argument ends on backslashes, make
+	      ;; sure to also escape them as they will be followed by
+	      ;; a comma.
+	      (concat arg (and (not (equal s ""))
+			       (string-match "\\\\+\\'" arg)
+			       (match-string 0 arg)))
+	      nil t)
+	     s)))))
+
+(defun org-macro-extract-arguments (s)
+  "Extract macro arguments from string S.
+S is a string containing comma separated values properly escaped.
+Return a list of arguments, as strings.  This is the opposite of
+`org-macro-escape-arguments'."
+  ;; Do not use `org-split-string' since empty strings are
+  ;; meaningful here.
+  (split-string
+   (replace-regexp-in-string
+    "\\(\\\\*\\),"
+    (lambda (str)
+      (let ((len (length (match-string 1 str))))
+	(concat (make-string (/ len 2) ?\\)
+		(if (zerop (mod len 2)) "\000" ","))))
+    s nil t)
+   "\000"))
+
 
 (provide 'org-macro)
 ;;; org-macro.el ends here

+ 24 - 0
testing/lisp/test-org-macro.el

@@ -76,6 +76,30 @@
       (org-macro-replace-all org-macro-templates)
       (buffer-string)))))
 
+(ert-deftest test-org-macro/escape-arguments ()
+  "Test `org-macro-escape-arguments' specifications."
+  ;; Regular tests.
+  (should (equal "a" (org-macro-escape-arguments "a")))
+  (should (equal "a,b" (org-macro-escape-arguments "a" "b")))
+  ;; Handle empty arguments.
+  (should (equal "a,,b" (org-macro-escape-arguments "a" "" "b")))
+  ;; Properly escape commas and backslashes preceding them.
+  (should (equal "a\\,b" (org-macro-escape-arguments "a,b")))
+  (should (equal "a\\\\,b" (org-macro-escape-arguments "a\\" "b")))
+  (should (equal "a\\\\\\,b" (org-macro-escape-arguments "a\\,b"))))
+
+(ert-deftest test-org-macro/extract-arguments ()
+  "Test `org-macro-extract-arguments' specifications."
+  ;; Regular tests.
+  (should (equal '("a") (org-macro-extract-arguments "a")))
+  (should (equal '("a" "b") (org-macro-extract-arguments "a,b")))
+  ;; Handle empty arguments.
+  (should (equal '("a" "" "b") (org-macro-extract-arguments "a,,b")))
+  ;; Handle escaped commas and backslashes.
+  (should (equal '("a,b") (org-macro-extract-arguments "a\\,b")))
+  (should (equal '("a\\" "b") (org-macro-extract-arguments "a\\\\,b")))
+  (should (equal '("a\\,b") (org-macro-extract-arguments "a\\\\\\,b"))))
+
 
 (provide 'test-org-macro)
 ;;; test-org-macro.el ends here