;;; xparse.el --- AUCTeX style for `xparse.sty' version 2020-03-06 -*- lexical-binding: t; -*- ;; Copyright (C) 2013, 2020 Free Software Foundation, Inc. ;; Maintainer: auctex-devel@gnu.org ;; Author: Mosè Giordano ;; Keywords: tex ;; This file is part of AUCTeX. ;; AUCTeX is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; AUCTeX is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with AUCTeX; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ;; 02110-1301, USA. ;;; Commentary: ;; This file adds basic support for `xparse.sty' version 2020-03-06. ;; It parses argument specification of macros and environments. ;; Currently, this style doesn't parse the embellishments specifiers ;; `e' and `E'. The "yet not more supported" specifiers `l', `u', `g' ;; and `G' are ignored completely and may lead to wrong parsing ;; results. ;;; Code: (require 'tex) (require 'latex) ;; Silence the compiler: (declare-function font-latex-add-keywords "font-latex" (keywords class)) (TeX-auto-add-type "xparse-macro" "LaTeX") (defvar LaTeX-xparse-macro-regexp `(,(concat (regexp-quote TeX-esc) "\\(?:New\\|Renew\\|Provide\\|Declare\\)" "\\(?:Expandable\\)?" "DocumentCommand" "[ \t\n\r]*" "{?" "[ \t\n\r]*" (regexp-quote TeX-esc) "\\([A-Za-z]+\\)" "[ \t\n\r]*" "}?" "[ \t\n\r]*" "{\\([^}{]*\\({[^}{]*\\({[^}{]*\\({[^}{]*}[^}{]*\\)*}[^}{]*\\)*}[^}{]*\\)*\\)}") (1 2) LaTeX-auto-xparse-macro) "Matches macros by xparse package.") (TeX-auto-add-type "xparse-environment" "LaTeX") (defvar LaTeX-xparse-environment-regexp `(,(concat (regexp-quote TeX-esc) "\\(?:New\\|Renew\\|Provide\\|Declare\\)" "DocumentEnvironment" "[ \t\n\r]*" "{" "[ \t\n\r]*" "\\([A-Za-z]+\\)" "[ \t\n\r]*" "}" "[ \t\n\r]*" "{\\([^}{]*\\({[^}{]*\\({[^}{]*\\({[^}{]*}[^}{]*\\)*}[^}{]*\\)*}[^}{]*\\)*\\)}") (1 2) LaTeX-auto-xparse-environment) "Matches environments by xparse package.") (defun LaTeX-arg-xparse-query (optional op-brace cl-brace &optional prompt) "Special query function for parsed elements from xparse package. If OPTIONAL is non-nil, indicate it in minibuffer. OP-BRACE sets the opening brace, CL-BRACE sets the closing one. PROMPT replaces the standard one." (let ((TeX-arg-opening-brace op-brace) (TeX-arg-closing-brace cl-brace)) (TeX-argument-insert (TeX-read-string (TeX-argument-prompt optional prompt "Text")) optional))) (defun LaTeX-xparse-macro-parse (type) "Process parsed macro and environment definitions. TYPE is one of the symobols mac or env." (dolist (xcmd (if (eq type 'mac) (LaTeX-xparse-macro-list) (LaTeX-xparse-environment-list))) (let ((name (car xcmd)) (spec (cadr xcmd)) args opt-star opt-token) (with-temp-buffer (set-syntax-table LaTeX-mode-syntax-table) ;; This one is probably not really needed? (goto-char (point-min)) (insert (replace-regexp-in-string "[ \t\r\n%]" "" spec)) (goto-char (point-min)) (while (looking-at-p "[+!>bmrRvodODsteE]") (cond (;; + or !: Long argument or space aware: Move over ;; them. b is special; only available for ;; enviroments (looking-at-p "[+!b]") (forward-char 1)) ((looking-at-p ">") ;; Argument processors: Move over > and a balanced ;; {} (forward-char 1) (forward-sexp)) ;; Mandatory arguments: ;; m: Ask for input with "Text" as prompt ((looking-at-p "m") (forward-char 1) (push "Text" args)) ;; r ((looking-at-p "r") (re-search-forward "r\\(?:\\(.\\)\\(.\\)\\)" (+ (point) 3) t) (push `(LaTeX-arg-xparse-query ,(match-string-no-properties 1) ,(match-string-no-properties 2)) args)) ;; R{default} ((looking-at-p "R") (re-search-forward "R\\(?:\\(.\\)\\(.\\)\\)" (+ (point) 3) t) (forward-sexp) (push `(LaTeX-arg-xparse-query ,(match-string-no-properties 1) ,(match-string-no-properties 2)) args)) ;; v: Use `TeX-arg-verb-delim-or-brace' ((looking-at-p "v") (forward-char 1) (push #'TeX-arg-verb-delim-or-brace args)) ;; Optional arguments: ;; o standard LaTeX optional in square brackets ((looking-at-p "o") (forward-char 1) (push (vector "Text") args)) ;; d ((looking-at-p "d") (re-search-forward "d\\(?:\\(.\\)\\(.\\)\\)" (+ (point) 3) t) (push (vector #'LaTeX-arg-xparse-query (match-string-no-properties 1) (match-string-no-properties 2)) args)) ;; O{default} ((looking-at-p "O") (forward-char 1) (forward-sexp) (push (vector "Text") args)) ;; D{default} ((looking-at-p "D") (re-search-forward "D\\(?:\\(.\\)\\(.\\)\\)" (+ (point) 3) t) (forward-sexp) (push (vector #'LaTeX-arg-xparse-query (match-string-no-properties 1) (match-string-no-properties 2)) args)) ;; s: optional star ((looking-at-p "s") (forward-char 1) (setq opt-star t)) ;; t: optional ((looking-at-p "t") (re-search-forward "t\\(.\\)" (+ (point) 2) t) (setq opt-token (match-string-no-properties 1))) ;; e & E are currently ignored. e: If looking at a ;; {, move one balanced expression, otherwise only ;; one character. ((looking-at-p "e") (forward-char) (if (looking-at-p TeX-grop) (forward-sexp) (forward-char))) ;; E ((looking-at-p "E") (forward-char) (if (looking-at-p TeX-grop) (forward-sexp) (forward-char)) (if (looking-at-p TeX-grop) (forward-sexp) (forward-char))) ;; Finished: (t nil)))) (if (eq type 'env) (LaTeX-add-environments `(,name LaTeX-env-args ,@(reverse (copy-sequence args)))) (TeX-add-symbols (cons name (reverse (copy-sequence args)))) (when opt-star (TeX-add-symbols (cons (concat name "*") (reverse (copy-sequence args))))) (when opt-token (TeX-add-symbols (cons (concat name opt-token) (reverse (copy-sequence args))))))))) (defun LaTeX-xparse-auto-prepare () "Clear various `LaTeX-auto-xparse-*' variables before parsing." (setq LaTeX-auto-xparse-macro nil LaTeX-auto-xparse-environment nil)) (defun LaTeX-xparse-auto-cleanup () "Process parsed elements for xparse package." (LaTeX-xparse-macro-parse 'mac) (LaTeX-xparse-macro-parse 'env)) (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) (TeX-auto-add-regexp LaTeX-xparse-environment-regexp) (TeX-run-style-hooks "expl3") (TeX-add-symbols ;; Declaring commands '("DeclareDocumentCommand" TeX-arg-define-macro "Argument specification" t) '("NewDocumentCommand" TeX-arg-define-macro "Argument specification" t) '("RenewDocumentCommand" TeX-arg-macro "Argument specification" t) '("ProvideDocumentCommand" TeX-arg-define-macro "Argument specification" t) ;; Declaring commands and environments '("DeclareDocumentEnvironment" TeX-arg-define-environment "Argument specification" t t) '("NewDocumentEnvironment" TeX-arg-define-environment "Argument specification" t t) '("RenewDocumentEnvironment" TeX-arg-environment "Argument specification" t t) '("ProvideDocumentEnvironment" TeX-arg-define-environment "Argument specification" t t) ;; Fully-expandable document commands '("DeclareExpandableDocumentCommand" TeX-arg-define-macro "Argument specification" t) '("NewExpandableDocumentCommand" TeX-arg-define-macro "Argument specification" t) '("RenewExpandableDocumentCommand" TeX-arg-macro "Argument specification" t) '("ProvideExpandableDocumentCommand" TeX-arg-define-macro "Argument specification" t) ;; Testing special values '("IfBooleanTF" 3) '("IfBooleanT" 3) '("IfBooleanF" 3) '("IfNoValueTF" 3) '("IfNoValueT" 3) '("IfNoValueF" 3) '("IfValueTF" 3) '("IfValueT" 3) '("IfValueF" 3) "BooleanTrue" "BooleanFalse" ;; Argument processors "ProcessedArgument" "ReverseBoolean" '("SplitArgument" "Number" "Token") "SplitList" "TrimSpaces" '("ProcessList" "List" "Functiom") ;; Access to the argument specification '("GetDocumentCommandArgSpec" TeX-arg-macro) '("GetDocumentEnvironmmentArgSpec" TeX-arg-environment) '("ShowDocumentCommandArgSpec" TeX-arg-macro) '("ShowDocumentEnvironmentArgSpec" TeX-arg-environment)) ;; Fontification (when (and (featurep 'font-latex) (eq TeX-install-font-lock 'font-latex-setup)) (font-latex-add-keywords '(("DeclareDocumentCommand" "|{\\{{") ("NewDocumentCommand" "|{\\{{") ("ProvideDocumentCommand" "|{\\{{") ("RenewDocumentCommand" "|{\\{{") ;; ("DeclareExpandableDocumentCommand" "|{\\{{") ("NewExpandableDocumentCommand" "|{\\{{") ("ProvideExpandableDocumentCommand" "|{\\{{") ("RenewExpandableDocumentCommand" "|{\\{{") ;; ("DeclareDocumentEnvironment" "{{{{") ("NewDocumentEnvironment" "{{{{") ("ProvideDocumentEnvironment" "{{{{") ("RenewDocumentEnvironment" "{{{{")) 'function))) TeX-dialect) (defun LaTeX-xparse-package-options () "Read the xparse package options from the user." (TeX-read-key-val t '(("log-declarations" ("true" "false"))))) ;;; xparse.el ends here