summaryrefslogtreecommitdiffstats
path: root/emacs.d/nxhtml/util/rnc-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'emacs.d/nxhtml/util/rnc-mode.el')
-rw-r--r--emacs.d/nxhtml/util/rnc-mode.el265
1 files changed, 265 insertions, 0 deletions
diff --git a/emacs.d/nxhtml/util/rnc-mode.el b/emacs.d/nxhtml/util/rnc-mode.el
new file mode 100644
index 0000000..5829a50
--- /dev/null
+++ b/emacs.d/nxhtml/util/rnc-mode.el
@@ -0,0 +1,265 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; A major mode for editing RELAX NG Compact syntax.
+;; Version: 1.0b3
+;; Date: 2002-12-05
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Copyright (c) 2002, Pantor Engineering AB
+;; All rights reserved.
+;;
+;; Redistribution and use in source and binary forms, with or
+;; without modification, are permitted provided that the following
+;; conditions are met:
+;;
+;; * Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;;
+;; * Redistributions in binary form must reproduce the above
+;; copyright notice, this list of conditions and the following
+;; disclaimer in the documentation and/or other materials provided
+;; with the distribution.
+;;
+;; * Neither the name of Pantor Engineering AB nor the names of its
+;; contributors may be used to endorse or promote products derived
+;; from this software without specific prior written permission.
+;;
+;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+;; CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+;; INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+;; BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+;; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+;; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+;; ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+;; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+;; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+;; POSSIBILITY OF SUCH DAMAGE.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Created by David.Rosenborg@pantor.com
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Example setup for your ~/.emacs file:
+;;
+;; (autoload 'rnc-mode "rnc-mode")
+;; (setq auto-mode-alist
+;; (cons '("\\.rnc\\'" . rnc-mode) auto-mode-alist))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Changes since 1.0b:
+;; Added a couple of defvars for faces to handle differences
+;; between GNU Emacs and XEmacs.
+;;
+;; 2008-12-28: Changed forward-char-command => forward-char
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'font-lock)
+
+(defvar rnc-indent-level 3 "The RNC indentation level.")
+
+(defvar rnc-keywords
+ (mapcar (lambda (kw) (concat "\\b" kw "\\b"))
+ '("attribute" "div" "element"
+ "empty" "external" "grammar" "include" "inherit" "list"
+ "mixed" "notAllowed" "parent" "start" "string"
+ "text" "token"))
+ "RNC keywords")
+
+(defvar rnc-atoms
+ (mapcar (lambda (kw) (concat "\\b" kw "\\b"))
+ '("empty" "notAllowed" "string" "text" "token"))
+ "RNC atomic pattern keywords")
+
+(defun rnc-make-regexp-choice (operands)
+ "(op1 op2 ...) -> \"\\(op1\\|op2\\|...\\)\""
+ (let ((result "\\("))
+ (mapc (lambda (op) (setq result (concat result op "\\|"))) operands)
+ (concat (substring result 0 -2) "\\)")))
+
+;; Font lock treats face names differently in GNU Emacs and XEmacs
+;; The following defvars is a workaround
+
+(defvar italic 'italic)
+(defvar default 'default)
+(defvar font-lock-preprocessor-face 'font-lock-preprocessor-face)
+
+(defvar rnc-font-lock-keywords
+ (list
+ '("\\b\\(attribute\\|element\\)\\b\\([^{]+\\){" 2
+ font-lock-variable-name-face)
+ '("[a-zA-Z][-a-zA-Z0-9._]*:[a-zA-Z][-a-zA-Z0-9._]*" . italic)
+ '("\\b\\(default\\(\\s +namespace\\)?\\|namespace\\|datatypes\\)\\(\\s +[a-zA-Z][-a-zA-Z0-9._]*\\)?\\s *=" 1 font-lock-preprocessor-face)
+ '("\\([a-zA-Z][-a-zA-Z0-9._]*\\)\\(\\s \\|\n\\)*[|&]?=" 1
+ font-lock-function-name-face)
+ '("[a-zA-Z][a-zA-Z0-9._]*\\(-[a-zA-Z][a-zA-Z0-9._]*\\)+" . default)
+ (cons (rnc-make-regexp-choice rnc-atoms) 'italic)
+ (cons (rnc-make-regexp-choice rnc-keywords) font-lock-keyword-face)
+ )
+ "RNC Highlighting")
+
+
+(defun rnc-find-column (first start)
+ "Find which column to indent to."
+
+ ;; FIXME: backward-sexp doesn't work with unbalanced braces in comments
+
+ (let* (column
+ pos
+ ;; Find start of enclosing block or assignment
+ (token
+ (if (member first '("]" "}" ")"))
+ (progn
+ (goto-char (+ start 1))
+ (backward-sexp)
+ (beginning-of-line)
+ (re-search-forward "\\S ")
+ (setq pos (point))
+ (setq column (- (current-column) 1))
+ 'lpar)
+ (catch 'done
+ (while (setq pos (re-search-backward "[{}()=]\\|\\[\\|\\]"
+ (point-min) t))
+ (let ((c (match-string 0)))
+ (beginning-of-line)
+ (re-search-forward "\\S ")
+ (setq column (- (current-column) 1))
+ (beginning-of-line)
+ (cond
+ ;; Don't match inside comments
+ ;; FIXME: Should exclude matches inside string literals too
+ ((re-search-forward "#" pos t) (beginning-of-line))
+ ;; Skip block
+ ((member c '("]" "}" ")"))
+ (goto-char (+ pos 1))
+ (backward-sexp))
+
+ ((string= c "=") (throw 'done 'eq))
+ (t (throw 'done 'lpar)))))))))
+
+ (cond
+ ((not pos) 0)
+ ((member first '("]" "}" ")")) column)
+ ((member first '("{" "(")) (+ column rnc-indent-level))
+
+ ;; Give lines starting with an operator a small negative indent.
+ ;; This allows for the following indentation style:
+ ;; foo =
+ ;; bar
+ ;; | baz
+ ;; | oof
+ ((member first '("," "&" "|")) (+ column (- rnc-indent-level 2)))
+
+ ;; Check if first preceding non-whitespace character was an operator
+ ;; If not, this is most likely a new assignment.
+ ;; FIXME: This doesn't play well with name classes starting on a new
+ ;; line
+ ((eq token 'eq)
+ (goto-char start)
+ (if (and (re-search-backward "[^ \t\n]" (point-min) t)
+ (member (match-string 0) '("&" "|" "," "=" "~")))
+ (+ column rnc-indent-level)
+ column))
+
+ (t (+ column rnc-indent-level)))))
+
+(defun rnc-indent-line ()
+ "Indents the current line."
+ (interactive)
+ (let ((orig-point (point)))
+ (beginning-of-line)
+ (let* ((beg-of-line (point))
+ (pos (re-search-forward "\\(\\S \\|\n\\)" (point-max) t))
+ (first (match-string 0))
+ (start (match-beginning 0))
+ (col (- (current-column) 1)))
+
+ (goto-char beg-of-line)
+
+ (let ((indent-column (rnc-find-column first start)))
+ (goto-char beg-of-line)
+
+ (cond
+ ;; Only modify buffer if the line must be reindented
+ ((not (= col indent-column))
+ (if (not (or (null pos)
+ (= beg-of-line start)))
+ (kill-region beg-of-line start))
+
+ (goto-char beg-of-line)
+
+ (while (< 0 indent-column)
+ (insert " ")
+ (setq indent-column (- indent-column 1))))
+
+ ((< orig-point start) (goto-char start))
+ (t (goto-char orig-point)))))))
+
+
+(defun rnc-electric-brace (arg)
+ (interactive "*P")
+ (self-insert-command (prefix-numeric-value arg))
+ (rnc-indent-line)
+ (let ((p (point)))
+ (when (save-excursion
+ (beginning-of-line)
+ (let ((pos (re-search-forward "\\S " (point-max) t)))
+ (and pos (= (- pos 1) p))))
+ (forward-char))))
+
+(defvar rnc-mode-map () "Keymap used in RNC mode.")
+(when (not rnc-mode-map)
+ (setq rnc-mode-map (make-sparse-keymap))
+ (define-key rnc-mode-map "\C-c\C-c" 'comment-region)
+ (define-key rnc-mode-map "}" 'rnc-electric-brace)
+ (define-key rnc-mode-map "{" 'rnc-electric-brace)
+ (define-key rnc-mode-map "]" 'rnc-electric-brace)
+ (define-key rnc-mode-map "[" 'rnc-electric-brace))
+
+;;;###autoload
+(defun rnc-mode ()
+ "Major mode for editing RELAX NG Compact Syntax schemas.
+\\{rnc-mode-map}"
+ (interactive)
+
+ (kill-all-local-variables)
+
+ (make-local-variable 'indent-line-function)
+ (setq indent-line-function 'rnc-indent-line)
+
+ (make-local-variable 'font-lock-defaults)
+ (setq font-lock-defaults '(rnc-font-lock-keywords nil t nil nil))
+
+ (use-local-map rnc-mode-map)
+
+ (make-local-variable 'comment-start)
+ (make-local-variable 'comment-end)
+ (make-local-variable 'comment-start-skip)
+
+ (setq comment-start "#"
+ comment-end ""
+ comment-start-skip "\\([ \n\t]+\\)##?[ \n\t]+")
+
+ (let ((rnc-syntax-table (copy-syntax-table)))
+ (modify-syntax-entry ?# "< " rnc-syntax-table)
+ (modify-syntax-entry ?\n "> " rnc-syntax-table)
+ (modify-syntax-entry ?\^m "> " rnc-syntax-table)
+ (modify-syntax-entry ?\\ "w " rnc-syntax-table)
+ (modify-syntax-entry ?' "\" " rnc-syntax-table)
+ (modify-syntax-entry ?. "w " rnc-syntax-table)
+ (modify-syntax-entry ?- "w " rnc-syntax-table)
+ (modify-syntax-entry ?_ "w " rnc-syntax-table)
+ (set-syntax-table rnc-syntax-table))
+
+ (setq mode-name "RNC"
+ major-mode 'rnc-mode)
+ (run-hooks 'rnc-mode-hook))
+
+(provide 'rnc-mode)