emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/rnc-mode cec8d2c 1/4: * rnc-mode: New package


From: Stefan Monnier
Subject: [elpa] externals/rnc-mode cec8d2c 1/4: * rnc-mode: New package
Date: Sat, 28 Nov 2020 18:20:03 -0500 (EST)

branch: externals/rnc-mode
commit cec8d2c4a1de04337d9881c16052e094bd2d69a5
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>

    * rnc-mode: New package
---
 rnc-mode.el | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 153 insertions(+)

diff --git a/rnc-mode.el b/rnc-mode.el
new file mode 100644
index 0000000..81f891b
--- /dev/null
+++ b/rnc-mode.el
@@ -0,0 +1,153 @@
+;;; rnc-mode.el --- Emacs mode to edit Relax-NG Compact files  -*- 
lexical-binding:t -*-
+
+;; Copyright (C) 1994-1998, 2001-2016 Free Software Foundation, Inc.
+
+;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
+;; Keywords: xml relaxng
+;; Version: 0.1
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+
+(require 'smie)
+(require 'nxml-mode)
+
+;;; Code:
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.rnc\\'" . rnc-mode))
+
+(defconst rnc-mode-syntax-table
+  (let ((st (make-syntax-table)))
+    (modify-syntax-entry ?# "<" st)
+    (modify-syntax-entry ?\n ">" st)
+    (modify-syntax-entry ?\" "\"" st)
+    (modify-syntax-entry ?- "_" st)
+    (modify-syntax-entry ?. "_" st)
+    (modify-syntax-entry ?: "_" st)
+    (modify-syntax-entry ?_ "_" st)
+    st))
+
+(defconst rnc--keywords
+  ;; Taken from the grammar in http://relaxng.org/compact-20021121.html,
+  ;; by order of appearance.
+  '("namespace" "default" "datatypes" "element" "attribute"
+    "list" "mixed" "parent" "empty" "text" "notAllowed" "external"
+    "grammar" "div" "include" ;; "start"
+    "string" "token" "inherit"))
+
+(defconst rnc--def-regexp "^[ \t]*\\([\\[:alpha:]][[:alnum:]-._]*\\)[ \t]*=")
+
+(defconst rnc-font-lock-keywords
+  `((,rnc--def-regexp (1 font-lock-function-name-face))
+    (,(concat "\\_<" (regexp-opt rnc--keywords) "\\_>")
+     (0 font-lock-keyword-face))
+    ("attribute[ \t\n]+\\([^ ]+\\)" (1 'nxml-attribute-local-name))
+    ;; FIXME: We'd like to use nxml-element-local-name for element names,
+    ;; but by default this looks exactly like font-lock-function-name-face,
+    ;; which we want to use for local pattern definitions.
+    ;; ("element[ \t\n]+\\([^ ]+\\)" (1 'nxml-element-local-name))
+    ))
+
+(defconst rnc-imenu-generic-expression `((nil ,rnc--def-regexp 1)))
+
+(defconst rnc-smie-grammar
+  ;; The body of an RNC file is a sequence of definitions.
+  ;; Problem is: these definitions are not separated by any special keyword.
+  ;; It's basically a repetition of (id "=" pattern), where
+  ;; patterns can end with:
+  ;;     "}", ")" "*", "+", "?", id, stringliteral
+  ;; Since this is way beyond the power of SMIE, we resort to using a pseudo
+  ;; " ; " separator which is introduced by the tokenizer.
+  (smie-prec2->grammar
+   (smie-bnf->prec2
+    '((id) (atom) (args)
+      (header (header "include" atom))
+      (decls (id "=" pattern) (id "|=" pattern) (id "&=" pattern)
+             (decls " ; " decls))
+      (pattern ("element" args) ("attribute" args)
+               ("list" args) ("mixed" args)
+               ("parent" id) ("external" id)
+               ("grammar" atom)
+              ("{" pattern "}")
+              (pattern "," pattern)
+              (pattern "&" pattern)
+              (pattern "|" pattern)
+              (pattern "?")
+              (pattern "*")
+              (pattern "+")))
+    ;; The spec says "There is no notion of operator precedence".
+    '((assoc " ; "))
+    '((assoc "," "&" "|") (nonassoc "?" "*" "+"))
+    )))
+
+(defun rnc-smie-forward-token ()
+  (let ((start (point)))
+    (forward-comment (point-max))
+    (if (and (> (point) start)
+             (looking-at "\\(?:\\s_\\|\\sw\\)+[ \t\n]*[|&]?=")
+             (save-excursion
+               (goto-char start)
+               (forward-comment -1)
+               (= (point) start)))
+        " ; "
+      (smie-default-forward-token))))
+
+(defun rnc-smie-backward-token ()
+  (let ((start (point)))
+    (forward-comment (- (point)))
+    (if (and (< (point) start)
+             (let ((pos (point)))
+               (goto-char start)
+               (prog1
+                   (looking-at "\\(?:\\s_\\|\\sw\\)+[ \t\n]*[|&]?=")
+                 (goto-char pos))))
+        " ; "
+      (smie-default-backward-token))))
+
+(defun rnc-smie-rules (kind token)
+  (pcase (cons kind token)
+    (`(:list-intro . "element") t)
+    (`(:before . ,(or "include" "default" "namespace" "datatypes")) 0)
+    (`(:before . "{")
+     (save-excursion
+       (let ((offset (if (smie-rule-bolp) smie-indent-basic 0))
+             x)
+         (while (or (null (car-safe x))
+                    (integerp (car-safe x)))
+           (setq x (smie-backward-sexp 'halfsexp)))
+         (goto-char (nth 1 x))
+         `(column . ,(+ (smie-indent-virtual) offset)))))
+    (`(:after . ,(or "=" "|=" "&=")) smie-indent-basic)
+    (`(:before . ,(or "|" "&" ","))
+     (and (smie-rule-bolp) (smie-rule-parent-p "(" "{") (smie-rule-parent)))
+    (`(,_ . " ; ") (smie-rule-separator kind))
+    ))
+
+;;;###autoload
+(define-derived-mode rnc-mode prog-mode "RNC"
+  "Major mode to edit Relax-NG Compact files."
+  (setq-local comment-start "#")
+  (setq-local font-lock-defaults '(rnc-font-lock-keywords))
+  (setq-local imenu-generic-expression rnc-imenu-generic-expression)
+  (smie-setup rnc-smie-grammar #'rnc-smie-rules
+              :forward-token #'rnc-smie-forward-token
+              :backward-token #'rnc-smie-backward-token))
+
+(provide 'rnc-mode)
+;;; rnc-mode.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]