From 42e1a6351df0a34197815d9701cf8b00b477703c Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Sat, 23 Mar 2013 19:10:41 +0100 Subject: [PATCH] org-element: Allow to escape escaping character before a comma * lisp/org-element.el (org-element-macro-parser): Allow to escape escaping character before a comma. Also do not trim spaces at argument boundaries. * doc/org.texi (Macro replacement): Update documentation about possible locations and escaping mechanism. * testing/lisp/test-org-element.el: Add tests. With this patch, macro's arguments are read as the following: "a,b" -> '("a" "b") "a\,b" -> '("a,b") "a\\,b" -> '("a\" "b") "a\\\,b" -> '("a\,b") "a\\\\,b" -> '(a"\\" "b") Note that with the patch, you only need to escape backslashes before a comma: "a\\b\,c" -> '("a\\b,c") --- doc/org.texi | 17 ++++++++++------- lisp/org-element.el | 21 ++++++++++----------- testing/lisp/test-org-element.el | 10 ++++++++++ 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/doc/org.texi b/doc/org.texi index 2ebc4086f..d859c6e84 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -9655,18 +9655,21 @@ You can define text snippets with #+MACRO: name replacement text $1, $2 are arguments @end example -@noindent which can be referenced anywhere in the document (even in -code examples) with @code{@{@{@{name(arg1,arg2)@}@}@}}. In addition to -defined macros, @code{@{@{@{title@}@}@}}, @code{@{@{@{author@}@}@}}, etc., -will reference information set by the @code{#+TITLE:}, @code{#+AUTHOR:}, and -similar lines. Also, @code{@{@{@{date(@var{FORMAT})@}@}@}} and +@noindent which can be referenced in +paragraphs, verse blocks, table cells and some keywords with +@code{@{@{@{name(arg1,arg2)@}@}@}}@footnote{Since commas separate arguments, +commas within arguments have to be escaped with a backslash character. +Conversely, backslash characters before a comma, and only them, need to be +escaped with another backslash character.}. In addition to defined macros, +@code{@{@{@{title@}@}@}}, @code{@{@{@{author@}@}@}}, etc., will reference +information set by the @code{#+TITLE:}, @code{#+AUTHOR:}, and similar lines. +Also, @code{@{@{@{date(@var{FORMAT})@}@}@}} and @code{@{@{@{modification-time(@var{FORMAT})@}@}@}} refer to current date time and to the modification time of the file being exported, respectively. @var{FORMAT} should be a format string understood by @code{format-time-string}. -Macro expansion takes place during export, and some people use it to -construct complex HTML code. +Macro expansion takes place during export. @node Embedded @LaTeX{}, , Macro replacement, Markup diff --git a/lisp/org-element.el b/lisp/org-element.el index ba2461a9e..3e6696930 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -3117,20 +3117,19 @@ Assume point is at the macro." (post-blank (progn (goto-char (match-end 0)) (skip-chars-forward " \t"))) (end (point)) - (args (let ((args (org-match-string-no-properties 3)) args2) + (args (let ((args (org-match-string-no-properties 3))) (when args ;; Do not use `org-split-string' since empty ;; strings are meaningful here. - (setq args (split-string args ",")) - (while args - (while (string-match "\\\\\\'" (car args)) - ;; Repair bad splits, when comma is protected, - ;; and thus not a real separator. - (setcar (cdr args) (concat (substring (car args) 0 -1) - "," (nth 1 args))) - (pop args)) - (push (pop args) args2)) - (mapcar 'org-trim (nreverse args2)))))) + (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"))))) (list 'macro (list :key key :value value diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el index 1294dc8f9..293a500a8 100644 --- a/testing/lisp/test-org-element.el +++ b/testing/lisp/test-org-element.el @@ -1345,6 +1345,16 @@ e^{i\\pi}+1=0 (should (equal '("C-,") (org-test-with-temp-text "{{{macro(C-\\,)}}}" + (org-element-property :args (org-element-context))))) + ;; Allow to escape escaping character. + (should + (equal '("C-\\" "") + (org-test-with-temp-text "{{{macro(C-\\\\,)}}}" + (org-element-property :args (org-element-context))))) + ;; No need to escape backslashes elsewhere. + (should + (equal '("\\") + (org-test-with-temp-text "{{{macro(\\)}}}" (org-element-property :args (org-element-context))))))