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")
This commit is contained in:
Nicolas Goaziou 2013-03-23 19:10:41 +01:00
parent 7847b4d7a8
commit 42e1a6351d
3 changed files with 30 additions and 18 deletions

View File

@ -9655,18 +9655,21 @@ You can define text snippets with
#+MACRO: name replacement text $1, $2 are arguments #+MACRO: name replacement text $1, $2 are arguments
@end example @end example
@noindent which can be referenced anywhere in the document (even in @noindent which can be referenced in
code examples) with @code{@{@{@{name(arg1,arg2)@}@}@}}. In addition to paragraphs, verse blocks, table cells and some keywords with
defined macros, @code{@{@{@{title@}@}@}}, @code{@{@{@{author@}@}@}}, etc., @code{@{@{@{name(arg1,arg2)@}@}@}}@footnote{Since commas separate arguments,
will reference information set by the @code{#+TITLE:}, @code{#+AUTHOR:}, and commas within arguments have to be escaped with a backslash character.
similar lines. Also, @code{@{@{@{date(@var{FORMAT})@}@}@}} and 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 @code{@{@{@{modification-time(@var{FORMAT})@}@}@}} refer to current date time
and to the modification time of the file being exported, respectively. and to the modification time of the file being exported, respectively.
@var{FORMAT} should be a format string understood by @var{FORMAT} should be a format string understood by
@code{format-time-string}. @code{format-time-string}.
Macro expansion takes place during export, and some people use it to Macro expansion takes place during export.
construct complex HTML code.
@node Embedded @LaTeX{}, , Macro replacement, Markup @node Embedded @LaTeX{}, , Macro replacement, Markup

View File

@ -3117,20 +3117,19 @@ Assume point is at the macro."
(post-blank (progn (goto-char (match-end 0)) (post-blank (progn (goto-char (match-end 0))
(skip-chars-forward " \t"))) (skip-chars-forward " \t")))
(end (point)) (end (point))
(args (let ((args (org-match-string-no-properties 3)) args2) (args (let ((args (org-match-string-no-properties 3)))
(when args (when args
;; Do not use `org-split-string' since empty ;; Do not use `org-split-string' since empty
;; strings are meaningful here. ;; strings are meaningful here.
(setq args (split-string args ",")) (split-string
(while args (replace-regexp-in-string
(while (string-match "\\\\\\'" (car args)) "\\(\\\\*\\)\\(,\\)"
;; Repair bad splits, when comma is protected, (lambda (str)
;; and thus not a real separator. (let ((len (length (match-string 1 str))))
(setcar (cdr args) (concat (substring (car args) 0 -1) (concat (make-string (/ len 2) ?\\)
"," (nth 1 args))) (if (zerop (mod len 2)) "\000" ","))))
(pop args)) args nil t)
(push (pop args) args2)) "\000")))))
(mapcar 'org-trim (nreverse args2))))))
(list 'macro (list 'macro
(list :key key (list :key key
:value value :value value

View File

@ -1345,6 +1345,16 @@ e^{i\\pi}+1=0
(should (should
(equal '("C-,") (equal '("C-,")
(org-test-with-temp-text "{{{macro(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)))))) (org-element-property :args (org-element-context))))))