Hi all,

I was thinking about how to extend xparse.el in order to parse argument
specs (which can be quite complicated) and now have a working setup --
diff and patched xparse.el are attached.  Main work is done by
`LaTeX-xparse-macro-parse'.  I don't have much experience with this kind
of parsing within Emacs.  Question: Is this kind of implementation
robust enough or are there better ways to do the job?

Here a small document I played with:

--8<---------------cut here---------------start------------->8---
\documentclass{article}

\usepackage{xparse}

\DeclareDocumentCommand \Foo { > { \ReverseBoolean } s o > { \SplitList { ; } } 
m r!! }{
  \ProcessList {#1} { \SomeDocumentFunction }
}

\begin{document}
C-c C-m Foo RET
\end{document}
--8<---------------cut here---------------end--------------->8---

Any comments welcome.

Best, Arash

diff --git a/style/xparse.el b/style/xparse.el
index d75f81c..672a609 100644
--- a/style/xparse.el
+++ b/style/xparse.el
@@ -30,12 +30,23 @@
 
 ;;; Code:
 
+;; Needed for auto-parsing.
+(require 'tex)
+
+(TeX-auto-add-type "xparse-macro" "LaTeX")
+
 (defvar LaTeX-xparse-macro-regexp
-  (concat "\\\\\\(?:Declare\\|New\\|Renew\\|Provide\\|DeclareExpandable\\)"
-	  "DocumentCommand[ \t\n\r]*{?[ \t\n\r]*\\\\\\([A-Za-z]+\\)[ \t\n\r]*}?"
-	  ;; The following is the opening brace of argument specification and is
-	  ;; needed to skip internal macros containing `:' or `_'.
-	  "[ \t\n\r]*{")
+  `(,(concat "\\\\\\(?:Declare\\|New\\|Renew\\|Provide\\|DeclareExpandable\\)"
+	     "DocumentCommand"
+	     "[ \t\n\r]*"
+	     "{?"
+	     "[ \t\n\r]*"
+	     "\\\\\\([A-Za-z]+\\)"
+	     "[ \t\n\r]*"
+	     "}?"
+	     "[ \t\n\r]*"
+	     "{\\([^}{]*\\({[^}{]*\\({[^}{]*\\({[^}{]*}[^}{]*\\)*}[^}{]*\\)*}[^}{]*\\)*\\)}")
+    (1 2) LaTeX-auto-xparse-macro)
   "Matches macros by xparse package.")
 
 (defvar LaTeX-xparse-environment-regexp
@@ -43,10 +54,88 @@
 	  "[ \t\n\r]*{[ \t\n\r]*\\([A-Za-z]+\\)[ \t\n\r]*}")
   "Matches environments by xparse package.")
 
+(defun LaTeX-xparse-auto-prepare ()
+  "Clear various `LaTeX-xparse-*' variables before parsing."
+  (setq LaTeX-auto-xparse-macro nil))
+
+(defun LaTeX-xparse-auto-cleanup ()
+  "Process parsed elements for xparse package."
+  (LaTeX-xparse-macro-parse))
+
+(defun LaTeX-xparse-macro-parse ()
+  "tbd"
+  (dolist (xcmd (LaTeX-xparse-macro-list))
+    (let ((macro (car xcmd))
+	  args
+	  have-arg
+	  have-star)
+      (with-temp-buffer
+	(insert (replace-regexp-in-string "[ \t\r\n+%]" "" (cadr xcmd)))
+	(goto-char (point-min))
+	(while (cond (;; Skip over Argument processors and return t
+		      (looking-at ">")
+		      (forward-char 1)
+		      (forward-sexp)
+		      t)
+		     ;; Mandatory arguments:
+		     ;; Add t for first occurrence, otherwise nil
+		     ((looking-at "[mlv]")
+		      (forward-char 1)
+		      (if have-arg
+			  (push nil args)
+			(progn
+			  (push t macro)
+			  (setq have-arg t))))
+		     ;; r <token1> <token2> with `TeX-arg-literal'
+		     ((looking-at "r")
+		      (save-excursion
+			(re-search-forward "r\\(..\\)" (+ (point) 3) t))
+		      (forward-char 3)
+		      (push `(TeX-arg-literal ,(match-string-no-properties 1)) args))
+		     ;; R <token1> <token2> {default skipped}, with `TeX-arg-literal'
+		     ((looking-at "R")
+		      (save-excursion
+			(re-search-forward "R\\(..\\)" (+ (point) 3) t))
+		      (forward-char 3)
+		      (forward-sexp)
+		      (push `(TeX-arg-literal ,(match-string-no-properties 1)) args))
+		     ;; Optional arguments:
+		     ((looking-at "o")
+		      (forward-char 1)
+		      (if have-arg
+			  (push (vector nil) args)
+			(progn
+			  (push (vector t) args)
+			  (setq have-arg t))))
+		     ((looking-at "d")
+		      (save-excursion
+			(re-search-forward "d\\(..\\)" (+ (point) 3) t))
+		      (forward-char 3)
+		      (push `(TeX-arg-literal ,(match-string-no-properties 1)) args))
+		     ((looking-at "O")
+		      (forward-char 1)
+		      (forward-sexp)
+		      (if have-arg
+			  (push (vector nil) args)
+			(progn
+			  (push (vector t) args)
+			  (setq have-arg t))))
+		     ((looking-at "s")
+		      (forward-char 1)
+		      (setq have-star t))
+		     (t nil))))
+      (TeX-add-symbols (append (list macro) (reverse args)))
+      (when have-star
+	(TeX-add-symbols (append (list (concat macro "*")) (reverse args)))))))
+
+(add-hook 'TeX-auto-prepare-hook #'LaTeX-xparse-auto-prepare t)
+(add-hook 'TeX-auto-cleanup-hook #'LaTeX-xparse-auto-cleanup t)
+(add-hook 'TeX-update-style-hook #'TeX-auto-parse t)
+
 (TeX-add-style-hook
  "xparse"
  (lambda ()
-   (TeX-auto-add-regexp `(,LaTeX-xparse-macro-regexp 1 TeX-auto-symbol))
+   (TeX-auto-add-regexp LaTeX-xparse-macro-regexp)
    (TeX-auto-add-regexp
     `(,LaTeX-xparse-environment-regexp 1 LaTeX-auto-environment))
    (TeX-run-style-hooks
@@ -95,7 +184,7 @@
    ;; Fontification
    (when (and (featurep 'font-latex)
 	      (eq TeX-install-font-lock 'font-latex-setup))
-     (font-latex-add-keywords '(("DeclareDocumentCommand" "|{{{")
+     (font-latex-add-keywords '(("DeclareDocumentCommand" "|{\\{{")
 				("NewDocumentCommand" "|{{{")
 				("RenewDocumentCommand" "|{{{")
 				("ProvideDocumentCommand" "|{{{")

Attachment: xparse.el
Description: application/emacs-lisp

_______________________________________________
auctex-devel mailing list
auctex-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/auctex-devel

Reply via email to