diff options
author | Nicolas Goaziou <mail@nicolasgoaziou.fr> | 2015-01-21 00:25:47 +0100 |
---|---|---|
committer | Nicolas Goaziou <mail@nicolasgoaziou.fr> | 2015-01-21 00:27:24 +0100 |
commit | ec0706ea40efd4d6048fe031b216586f1e32c27b (patch) | |
tree | 78d8dd2141aaab995a9add899f5110b93911b545 | |
parent | a84c467b8ee7b97218ac789ce11c417217c627d2 (diff) | |
download | org-mode-ec0706ea40efd4d6048fe031b216586f1e32c27b.tar.gz |
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.
-rw-r--r-- | lisp/org-element.el | 13 | ||||
-rw-r--r-- | lisp/org-macro.el | 45 | ||||
-rw-r--r-- | testing/lisp/test-org-macro.el | 24 |
3 files changed, 70 insertions, 12 deletions
diff --git a/lisp/org-element.el b/lisp/org-element.el index d5d4bb9..3478421 100644 --- a/lisp/org-element.el +++ b/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 diff --git a/lisp/org-macro.el b/lisp/org-macro.el index 923e377..60b2982 100644 --- a/lisp/org-macro.el +++ b/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 diff --git a/testing/lisp/test-org-macro.el b/testing/lisp/test-org-macro.el index 524ad62..d28cb7f 100644 --- a/testing/lisp/test-org-macro.el +++ b/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 |