summaryrefslogtreecommitdiffstats
path: root/emacs.d/nxhtml/nxhtml/rngalt.el
diff options
context:
space:
mode:
Diffstat (limited to 'emacs.d/nxhtml/nxhtml/rngalt.el')
-rw-r--r--emacs.d/nxhtml/nxhtml/rngalt.el828
1 files changed, 828 insertions, 0 deletions
diff --git a/emacs.d/nxhtml/nxhtml/rngalt.el b/emacs.d/nxhtml/nxhtml/rngalt.el
new file mode 100644
index 0000000..788128a
--- /dev/null
+++ b/emacs.d/nxhtml/nxhtml/rngalt.el
@@ -0,0 +1,828 @@
+;;; rngalt.el --- Tools for making completion addition to nxml mode
+;;
+;; Author: Lennart Borgman
+;; Created: Wed Jan 10 17:17:18 2007
+(defconst rngalt:version "0.51") ;;Version:
+;; Last-Updated: 2008-03-08T03:33:56+0100 Sat
+;; Keywords:
+;; Compatibility:
+;;
+;; Features that might be required by this library:
+;;
+;; `nxml-enc', `nxml-ns', `nxml-parse', `nxml-util',
+;; `ourcomments-util', `rng-dt', `rng-loc', `rng-match',
+;; `rng-parse', `rng-pttrn', `rng-uri', `rng-util', `rng-valid',
+;; `xmltok'.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Commentary:
+;;
+;;
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Change log:
+;;
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; This program 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 2, or (at your option)
+;; any later version.
+;;
+;; This program 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 this program; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Code:
+
+(eval-and-compile (require 'rng-valid))
+(eval-when-compile (require 'rng-nxml))
+(eval-when-compile (unless load-file-name (require 'nxhtml-mode nil t)))
+
+(eval-when-compile
+ (let* ((this-file (or load-file-name
+ (when (boundp 'bytecomp-filename) bytecomp-filename)
+ buffer-file-name))
+ (this-dir (file-name-directory this-file))
+ (util-dir (expand-file-name "../util/" this-dir))
+ (load-path (cons util-dir load-path)))
+ (require 'ourcomments-util)))
+;;(require 'ourcomments-util)
+
+;; (setq x (macroexpand '(defcustom my-temp-opt t "doc" :type 'boolean)))
+;; (setq x (macroexpand '(define-minor-mode my-temp-mode "doc")))
+;; (setq x (macroexpand '(define-toggle my-temp-toggle t "doc")))
+;;(define-toggle rngalt-display-validation-header t
+(define-minor-mode rngalt-display-validation-header
+ "Display XML validation headers at the top of buffer when t.
+The validation header is only displayed in buffers where the main
+major mode is derived from `nxml-mode'."
+ :global t
+ :init-value t
+ :group 'relax-ng
+ :group 'nxhtml
+ (when (fboundp 'rngalt-update-validation-header-overlay-everywhere)
+ (rngalt-update-validation-header-overlay-everywhere)))
+
+(defun rngalt-display-validation-header-toggle ()
+ "Toggle `rngalt-display-validation-header'."
+ (interactive)
+ (rngalt-display-validation-header (if rngalt-display-validation-header -1 1)))
+
+;;(define-toggle rngalt-minimal-validation-header t
+(define-minor-mode rngalt-minimal-validation-header
+ "If non-nil display only a short informaion about the XML validation header.
+See also `rngalt-display-validation-header'."
+ :global t
+ :init-value t
+ :group 'relax-ng
+ :group 'nxhtml
+ (when (fboundp 'rngalt-update-validation-header-overlay-everywhere)
+ (rngalt-update-validation-header-overlay-everywhere)))
+
+(defun rngalt-minimal-validation-header-toggle ()
+ "Toggle `rngalt-minimal-validation-header'."
+ (interactive)
+ (rngalt-minimal-validation-header (if rngalt-minimal-validation-header -1 1)))
+
+(defface rngalt-validation-header-top
+ '((t (:foreground "RGB:87/CE/FA" :background "white")))
+ "Face first line of validation header."
+ :group 'nxhtml)
+
+(defface rngalt-validation-header-bottom
+ '((t (:foreground "white" :background "RGB:87/CE/FA")))
+ "Face first line of validation header."
+ :group 'nxhtml)
+
+;; FIX-ME: remember to clear these variable, but where?
+(defvar rngalt-validation-header nil)
+(make-variable-buffer-local 'rngalt-validation-header)
+(put 'rngalt-validation-header 'permanent-local t)
+
+(defvar rngalt-current-schema-file-name nil)
+(make-variable-buffer-local 'rngalt-current-schema-file-name)
+(put 'rngalt-current-schema-file-name 'permanent-local t)
+
+(defvar rngalt-validation-header-overlay nil)
+(make-variable-buffer-local 'rngalt-validation-header-overlay)
+(put 'rngalt-validation-header-overlay 'permanent-local t)
+
+(defvar rngalt-major-mode nil)
+(make-variable-buffer-local 'rngalt-major-mode)
+(put 'rngalt-major-mode 'permanent-local t)
+
+(defvar rngalt-complete-first-try nil
+ "First function to try for completion.
+If non-nil should be a function with no parameters. Used by
+`rngalt-complete'.")
+
+(defvar rngalt-complete-last-try nil
+ "Last function to try for completion.
+If non-nil should be a function with no parameters. Used by
+`rngalt-complete'.")
+
+(defvar rngalt-completing-read-tag nil
+ "Alternate function for completing tag name.
+If non-nil should be a function with the same parameters as
+`completing-read'. Used by `rngalt-complete'.")
+
+(defvar rngalt-completing-read-attribute-name nil
+ "Alternate function for completing attribute name.
+If non-nil should be a function with the same parameters as
+`completing-read'. Used by `rngalt-complete'.")
+
+(defvar rngalt-completing-read-attribute-value nil
+ "Alternate function for completing attribute value.
+If non-nil should be a function with the same parameters as
+`completing-read'. Used by `rngalt-complete'.")
+
+
+(defun rngalt-finish-element ()
+ "Finish the current element by inserting an end-tag.
+Like `nxml-finish-element' but takes `rngalt-validation-header'
+into account."
+ (interactive "*")
+ (rngalt-finish-element-1 nil))
+
+;; Fix-me: Check the other uses of `nxml-finish-element-1'. But this
+;; is maybe not necessary since the only other use is in
+;; `nxml-split-element' and that will anyway work - I believe ...
+(defun rngalt-finish-element-1 (startp)
+ "Insert an end-tag for the current element and optionally a start-tag.
+The start-tag is inserted if STARTP is non-nil. Return the position
+of the inserted start-tag or nil if none was inserted.
+
+This is like `nxml-finish-element-1' but takes
+`rngalt-validation-header' into account."
+ (interactive "*")
+ (let (token-end
+ start-tag-end
+ starts-line
+ ends-line
+ start-tag-indent
+ qname
+ inserted-start-tag-pos)
+ ;; Temporary insert the fictive validation header if any.
+ (let ((buffer-undo-list nil)
+ (here (point-marker)))
+ (when rngalt-validation-header
+ (let ((vh (nth 2 rngalt-validation-header)))
+ (set-marker-insertion-type here t)
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (insert vh)))
+ (goto-char here))
+ (setq token-end (nxml-token-before))
+ (setq start-tag-end
+ (save-excursion
+ (when (and (< (point) token-end)
+ (memq xmltok-type
+ '(cdata-section
+ processing-instruction
+ comment
+ start-tag
+ end-tag
+ empty-element)))
+ (error "Point is inside a %s"
+ (nxml-token-type-friendly-name xmltok-type)))
+ (nxml-scan-element-backward token-end t)))
+ (when start-tag-end
+ (setq starts-line
+ (save-excursion
+ (unless (eq xmltok-type 'start-tag)
+ (error "No matching start-tag"))
+ (goto-char xmltok-start)
+ (back-to-indentation)
+ (eq (point) xmltok-start)))
+ (setq ends-line
+ (save-excursion
+ (goto-char start-tag-end)
+ (looking-at "[ \t\r\n]*$")))
+ (setq start-tag-indent (save-excursion
+ (goto-char xmltok-start)
+ (current-column)))
+ (setq qname (xmltok-start-tag-qname)))
+
+ ;; Undo the insertion of the fictive header:
+ (undo-start)
+ (while (and (not (eq t pending-undo-list))
+ pending-undo-list)
+ (undo-more 1))
+ (goto-char here))
+
+ (unless start-tag-end (error "No more start tags"))
+
+ (when (and starts-line ends-line)
+ ;; start-tag is on a line by itself
+ ;; => put the end-tag on a line by itself
+ (unless (<= (point)
+ (save-excursion
+ (back-to-indentation)
+ (point)))
+ (insert "\n"))
+ (indent-line-to start-tag-indent))
+ (insert "</" qname ">")
+ (when startp
+ (when starts-line
+ (insert "\n")
+ (indent-line-to start-tag-indent))
+ (setq inserted-start-tag-pos (point))
+ (insert "<" qname ">")
+ (when (and starts-line ends-line)
+ (insert "\n")
+ (indent-line-to (save-excursion
+ (goto-char xmltok-start)
+ (forward-line 1)
+ (back-to-indentation)
+ (if (= (current-column)
+ (+ start-tag-indent nxml-child-indent))
+ (+ start-tag-indent nxml-child-indent)
+ start-tag-indent)))))
+ inserted-start-tag-pos))
+
+(defun rngalt-complete ()
+ "Complete the string before point using the current schema.
+Return non-nil if in a context it understands.
+
+This function should be added to `nxml-completion-hook' before
+`rng-complete'. By default it works just like this function, but
+you can add your own completion by setting the variables
+`rngalt-complete-first-try', `rngalt-completing-read-tag',
+`rngalt-completing-read-attribute-name',
+`rngalt-completing-read-attribute-value' and
+`rngalt-complete-last-try'."
+ (interactive)
+ (unless rng-validate-mode
+ (when (y-or-n-p
+ "XML Validation is not on. Do you want to turn it on? ")
+ (rng-validate-mode 1)))
+ (when rng-validate-mode
+ ;; schema file may mismatch if user sets it explicitly:
+ (rngalt-reapply-validation-header)
+ (when rng-current-schema-file-name
+ (rngalt-validate))
+ (or (when rngalt-complete-first-try
+ (funcall rngalt-complete-first-try))
+ (progn
+ (unless rng-current-schema-file-name
+ (when (eq major-mode 'nxhtml-mode)
+ (when (y-or-n-p
+ "There is currently no DTD specified for the buffer.
+This makes XHTML completion impossible. You can add a fictive
+XHTML validation header that sets the DTD to XHTML. This will
+not be inserted in the buffer but completion and XHTML validation
+will assume it is there so both error checking and completion
+will work.
+
+Do you want to add a fictive XHTML validation header? ")
+ (message "") ;; Get rid of the large minibuffer message window
+ (nxhtml-validation-header-mode)
+ )))
+ (let ((lt-pos (save-excursion (search-backward "<" nil t)))
+ xmltok-dtd)
+ (or (and lt-pos
+ (= (rng-set-state-after lt-pos) lt-pos)
+ (or (rngalt-complete-tag lt-pos)
+ (rng-complete-end-tag lt-pos)
+ (rngalt-complete-attribute-name lt-pos)
+ (rngalt-complete-attribute-value lt-pos)))
+ (when rngalt-complete-last-try
+ (funcall rngalt-complete-last-try))))))))
+
+(defun rngalt-validate ()
+ (unless (= (buffer-size) 0)
+ (let ((while-n1 0)
+ (maxn1 20))
+ (condition-case err
+ (while (and (> maxn1 (setq while-n1 (1+ while-n1)))
+ (rng-do-some-validation))
+ nil)
+ (error
+ ;; FIX-ME: for debugging:
+ ;;(lwarn 'rngalt-validate :error "%s" (error-message-string err))
+ (message "rngalt-validate: %s" (error-message-string err))
+ nil))
+ (when (>= while-n1 maxn1)
+ (error "rngalt-validate: Could not validate")))
+ (rng-validate-done)))
+
+(defvar rngalt-region-ovl nil)
+(defvar rngalt-region-prepared nil)
+(defun rngalt-complete-tag-region-prepare ()
+ (unless rngalt-region-prepared
+ (when rngalt-region-ovl
+ (when (overlayp rngalt-region-ovl)
+ (delete-overlay rngalt-region-ovl))
+ (setq rngalt-region-ovl nil))
+ (when (and mark-active
+ transient-mark-mode)
+ (let ((beginning (region-beginning))
+ (end (region-end)))
+ (unless (= (point) (region-beginning))
+ (goto-char beginning))
+ (when (save-excursion
+ (when (re-search-forward "\\=[^<]*\\(?:<[^<]*>\\)*[^>]*" end t)
+ (= end (point))))
+ (setq rngalt-region-ovl (make-overlay beginning end))
+ (overlay-put rngalt-region-ovl 'face 'region)
+ )))
+ (setq rngalt-region-prepared t)))
+
+(defun rngalt-complete-tag-region-cleanup ()
+ (when rngalt-region-prepared
+ (when (overlayp rngalt-region-ovl)
+ (delete-overlay rngalt-region-ovl))
+ (deactivate-mark)
+ (setq rngalt-region-prepared nil)))
+
+(defun rngalt-complete-tag-region-finish ()
+ (when (and rngalt-region-prepared
+ (overlayp rngalt-region-ovl))
+ (let ((here (point)))
+ (insert ">")
+ (goto-char (overlay-end rngalt-region-ovl))
+ (nxml-finish-element)
+ (rngalt-validate)
+ (goto-char here)))
+ (rngalt-complete-tag-region-cleanup))
+
+(defun rngalt-complete-tag (lt-pos)
+ "Like `rng-complete-tag' but with some additions.
+The additions are:
+- Alternate completion.
+- Complete around highlighted region.
+
+See also the variable `rngalt-completing-read-tag'."
+ (let (rng-complete-extra-strings)
+ (when (and (= lt-pos (1- (point)))
+ rng-complete-end-tags-after-<
+ rng-open-elements
+ (not (eq (car rng-open-elements) t))
+ (or rng-collecting-text
+ (rng-match-save
+ (rng-match-end-tag))))
+ (setq rng-complete-extra-strings
+ (cons (concat "/"
+ (if (caar rng-open-elements)
+ (concat (caar rng-open-elements)
+ ":"
+ (cdar rng-open-elements))
+ (cdar rng-open-elements)))
+ rng-complete-extra-strings)))
+ (when (save-excursion
+ (re-search-backward rng-in-start-tag-name-regex
+ lt-pos
+ t))
+ (and rng-collecting-text (rng-flush-text))
+ (rngalt-complete-tag-region-prepare)
+ (let ((completion
+ (let ((rng-complete-target-names
+ (rng-match-possible-start-tag-names))
+ (rng-complete-name-attribute-flag nil))
+ (rngalt-complete-before-point (1+ lt-pos)
+ 'rng-complete-qname-function
+ "Insert tag: "
+ nil
+ 'rng-tag-history
+ rngalt-completing-read-tag)))
+ name)
+ (when completion
+ (cond ((rng-qname-p completion)
+ (setq name (rng-expand-qname completion
+ t
+ 'rng-start-tag-expand-recover))
+ (when (and name
+ (rng-match-start-tag-open name)
+ (or (not (rng-match-start-tag-close))
+ ;; need a namespace decl on the root element
+ (and (car name)
+ (not rng-open-elements))))
+ ;; attributes are required
+ (insert " "))
+ (rngalt-complete-tag-region-finish)
+ (run-hook-with-args 'rngalt-complete-tag-hooks completion)
+ )
+ ((member completion rng-complete-extra-strings)
+ (insert ">")))))
+ (rngalt-complete-tag-region-finish)
+ t)))
+
+(defvar rngalt-complete-tag-hooks nil
+ "Hook run after completing a tag.
+Each function is called with the last name of the last tag
+completed.")
+
+(defun rngalt-complete-attribute-name (lt-pos)
+ "Like `rng-complete-attribute-name' but with alternate completion.
+See the variable `rngalt-completing-read-attribute-name'."
+ (when (save-excursion
+ (re-search-backward rng-in-attribute-regex lt-pos t))
+ (let ((attribute-start (match-beginning 1))
+ rng-undeclared-prefixes)
+ (and (rng-adjust-state-for-attribute lt-pos
+ attribute-start)
+ (let ((rng-complete-target-names
+ (rng-match-possible-attribute-names))
+ (rng-complete-extra-strings
+ (mapcar (lambda (prefix)
+ (if prefix
+ (concat "xmlns:" prefix)
+ "xmlns"))
+ rng-undeclared-prefixes))
+ (rng-complete-name-attribute-flag t)
+ completion)
+ (setq completion
+ (rngalt-complete-before-point attribute-start
+ 'rng-complete-qname-function
+ "Attribute: "
+ nil
+ 'rng-attribute-name-history
+ rngalt-completing-read-attribute-name))
+ (when (and completion
+ (< 0 (length completion)))
+ (insert "=\"")))))
+ t))
+
+(defun rngalt-complete-attribute-value (lt-pos)
+ "Like `rng-complete-attribute-value' but with alternate completion.
+See the variable `rngalt-completing-read-attribute-value'."
+ (when (save-excursion
+ (re-search-backward rng-in-attribute-value-regex lt-pos t))
+ (let ((name-start (match-beginning 1))
+ (name-end (match-end 1))
+ (colon (match-beginning 2))
+ (value-start (1+ (match-beginning 3))))
+ (and (rng-adjust-state-for-attribute lt-pos
+ name-start)
+ (if (string= (buffer-substring-no-properties name-start
+ (or colon name-end))
+ "xmlns")
+ (rngalt-complete-before-point
+ value-start
+ (rng-strings-to-completion-alist
+ (rng-possible-namespace-uris
+ (and colon
+ (buffer-substring-no-properties (1+ colon) name-end))))
+ "Namespace URI: "
+ nil
+ 'rng-namespace-uri-history
+ rngalt-completing-read-attribute-value) ;; fix-me
+ (rng-adjust-state-for-attribute-value name-start
+ colon
+ name-end)
+ (rngalt-complete-before-point
+ value-start
+ (rng-strings-to-completion-alist
+ (rng-match-possible-value-strings))
+ "Value: "
+ nil
+ 'rng-attribute-value-history
+ rngalt-completing-read-attribute-value))
+ (unless (eq (char-after) (char-before value-start))
+ (insert (char-before value-start)))))
+ t))
+
+(defun rngalt-complete-before-point (start table prompt &optional predicate hist altcompl)
+ "Complete text between START and point.
+Works like `rng-complete-before-point' if ALTCOMPL is nil. When
+ALTCOMPL is a function symbol and no completion alternative is
+available from table then this is called instead of
+`compleating-read' with the same parameters."
+ (let* ((orig (buffer-substring-no-properties start (point)))
+ (completion (try-completion orig table predicate))
+ (completing-fun (if altcompl altcompl 'completing-read))
+ (completion-ignore-case t))
+ (cond ((not (or completion completing-fun))
+ (if (string= orig "")
+ (message "No completions available")
+ (message "No completion for %s" (rng-quote-string orig)))
+ (ding)
+ nil)
+ ((eq completion t) orig)
+ ((and completion
+ (not (string= completion orig)))
+ (delete-region start (point))
+ (insert completion)
+ (cond ((not (rng-completion-exact-p completion table predicate))
+ (message "Incomplete")
+ nil)
+ ((eq (try-completion completion table predicate) t)
+ completion)
+ (t
+ (message "Complete but not unique")
+ nil)))
+ (t
+ (setq completion
+ (let ((saved-minibuffer-setup-hook
+ (default-value 'minibuffer-setup-hook)))
+ (add-hook 'minibuffer-setup-hook
+ 'minibuffer-completion-help
+ t)
+ (unwind-protect
+ (funcall completing-fun
+ prompt
+ table
+ predicate
+ nil
+ orig
+ hist)
+ (setq-default minibuffer-setup-hook
+ saved-minibuffer-setup-hook))))
+ (when completion
+ (delete-region start (point))
+ (insert completion))
+ completion))))
+
+(defun rngalt-get-missing-required-attr (single-tag)
+ "Get a list of missing required attributes.
+This is to be used when completing attribute names.
+SINGLE-TAG should be non-nil if the tag has no end tag.
+
+For a typical use see `nxhtml-completing-read-attribute-name' in
+nxhtml.el.
+"
+ ;; FIX-ME: This is a terrible cludge. One day I hope I will
+ ;; understand how to write this ;-)
+ ;;
+ ;; I currently fetch the missing tags from the error message in the
+ ;; error overlay set by rng validate.
+ (let ((here (point)))
+ (unless (save-match-data (looking-at "[^<]\\{,200\\}>"))
+ ;; We can probably add a >, so let us do it:
+ (when single-tag
+ (insert "/"))
+ (insert ">")
+ (rngalt-validate))
+ (goto-char here))
+ (let ((ovl (rng-error-overlay-message (or (rng-error-overlay-after (point))
+ (rng-error-overlay-after (1- (point)))))))
+ ;;(message "ovl=%s" ovl)(sit-for 1)
+ ;;(message "prop ovl=%s" (overlay-properties ovl))(sit-for 1)
+ (when (and ovl
+ (eq (overlay-get ovl 'category) 'rng-error))
+ ;;(message "rng-error")(sit-for 1)
+ (let ((msg (overlay-get ovl 'help-echo)))
+ ;;(message "msg=%s" msg);(sit-for 1)
+ (when (string-match "Missing attributes? \\(.*\\)" msg)
+ ;;(message "0=%s" (match-string 0 msg));(sit-for 1)
+ ;;(message "1=%s" (match-string 1 msg));(sit-for 1)
+ (let* ((matches (match-string 1 msg))
+ (lst (split-string (substring matches 1 (- (length matches) 1)) "\", \"")))
+ ;;(message "matches=%s" matches);(sit-for 2)
+ ;;(message "lst=%s" lst);(sit-for 1)
+ lst))))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Validation start state
+
+(defun rngalt-after-change-major ()
+ (unless (and (boundp 'mumamo-set-major-running)
+ mumamo-set-major-running)
+ (setq rngalt-major-mode major-mode)
+ (when (and (derived-mode-p 'nxml-mode)
+ rngalt-validation-header)
+ (rngalt-reapply-validation-header))
+ (rngalt-update-validation-header-overlay)))
+
+(defvar rngalt-validation-header-keymap
+ (let ((map (make-sparse-keymap)))
+ (define-key map [mouse-1] 'rngalt-minimal-validation-header-toggle)
+ map))
+
+(defun rngalt-update-validation-header-overlay ()
+ (if (and (boundp 'rngalt-display-validation-header)
+ rngalt-display-validation-header
+ rngalt-validation-header
+ (or (derived-mode-p 'nxml-mode)
+ (let ((major-mode rngalt-major-mode))
+ (and major-mode
+ (derived-mode-p 'nxml-mode))))
+ )
+ (progn
+ (if rngalt-validation-header-overlay
+ (move-overlay rngalt-validation-header-overlay 1 1)
+ (setq rngalt-validation-header-overlay (make-overlay 1 1)))
+ (overlay-put rngalt-validation-header-overlay
+ 'priority 1000)
+ ;; Other properties should go to the 'before-string
+ (let* ((validation-header (nth 2 rngalt-validation-header))
+ (header
+ (if rngalt-minimal-validation-header
+ (propertize
+ (concat
+ "*** Fictive XHTML/XML Validation Header: ... "
+ (save-match-data
+ (if (string-match "\\(<[^[:space:]>]+\\)[^>]*>[^<>]*\\'"
+ validation-header)
+ (concat (match-string 1 validation-header) ">")
+ "Error"))
+ "\n")
+ 'face 'rngalt-validation-header-bottom)
+ (concat
+ (propertize "*** Fictive XHTML/XML Validation Header:\n"
+ 'face 'rngalt-validation-header-top)
+ (propertize (concat validation-header "\n")
+ 'face 'rngalt-validation-header-bottom)))))
+ (setq header
+ (propertize
+ header
+ 'help-echo
+ "Click to toggle full/minimal display of header"
+ 'keymap rngalt-validation-header-keymap))
+ (overlay-put rngalt-validation-header-overlay
+ 'before-string header)))
+ (when rngalt-validation-header-overlay
+ (delete-overlay rngalt-validation-header-overlay))))
+
+(defun rngalt-update-validation-header-overlay-everywhere ()
+ (dolist (b (buffer-list))
+ (when (buffer-live-p b)
+ (with-current-buffer b
+ (when rngalt-validation-header
+ (rngalt-update-validation-header-overlay))))))
+
+;; This is exactly the same as the original `rng-set-initial-state'
+;; except when `rngalt-validation-header' is non-nil."
+(defadvice rng-set-initial-state (around
+ rngalt-set-initial-state
+ activate
+ compile
+ )
+ (nxml-ns-init)
+ (rng-match-start-document)
+ (setq rng-open-elements nil)
+ (setq rng-pending-contents nil)
+ (when rngalt-validation-header
+ (let ((state (car rngalt-validation-header)))
+ (rng-restore-state state)))
+ (setq ad-return-value (goto-char (point-min))))
+
+;; (defun rng-new-validate-prepare ()
+;; "Prepare to do some validation, initializing point and the state.
+;; Return t if there is work to do, nil otherwise.
+
+;; This is exactly the same as the original-insert-directory
+;; `rng-validate-prepare' with the difference that the state at
+;; point 1 is set differently if `rngalt-validation-header' is
+;; non-nil.
+
+;; See also `rng-set-initial-state'."
+;; (cond ((= rng-validate-up-to-date-end 1)
+;; (rng-set-initial-state)
+;; t)
+;; ((= rng-validate-up-to-date-end (point-max))
+;; nil)
+;; (t (let ((state
+;; (if (and rngalt-validation-header
+;; (= rng-validate-up-to-date-end 1))
+;; (car rngalt-validation-header)
+;; (get-text-property (1- rng-validate-up-to-date-end)
+;; 'rng-state))))
+;; (cond (state
+;; (rng-restore-state state)
+;; (goto-char rng-validate-up-to-date-end))
+;; (t
+;; (let ((pos (previous-single-property-change
+;; rng-validate-up-to-date-end
+;; 'rng-state)))
+;; (cond (pos
+;; (rng-restore-state
+;; (or (get-text-property (1- pos) 'rng-state)
+;; (error "Internal error: state null")))
+;; (goto-char pos))
+;; (t (rng-set-initial-state))))))))))
+
+
+;; For as-external.el
+;;;###autoload
+(defun rngalt-set-validation-header (start-of-doc)
+ (let ((old-rvm rng-validate-mode))
+ (when old-rvm (rng-validate-mode -1))
+ (if start-of-doc
+ (progn
+ (add-hook 'after-change-major-mode-hook 'rngalt-after-change-major nil t)
+ (setq rngalt-validation-header (rngalt-get-state-after start-of-doc))
+ (rng-set-schema-file-1 (cadr rngalt-validation-header))
+ (setq rngalt-current-schema-file-name rng-current-schema-file-name)
+ (setq rng-compile-table nil)
+ (setq rng-ipattern-table nil)
+ (setq rng-last-ipattern-index nil))
+ (remove-hook 'after-change-major-mode-hook 'rngalt-after-change-major t)
+ (setq rngalt-validation-header nil)
+ (when old-rvm
+ (rng-set-vacuous-schema)
+ (rng-auto-set-schema)))
+ (when old-rvm
+ (rng-validate-mode 1)
+ (rngalt-update-validation-header-overlay)
+ (rngalt-update-validation-header-buffer))))
+
+(defun rngalt-reapply-validation-header ()
+ (when rngalt-validation-header
+ (when (or (not rng-current-schema-file-name)
+ (unless (string= rngalt-current-schema-file-name rng-current-schema-file-name)
+ (lwarn 'schema-mismatch :warning
+ "XHTML validation header schema %s reapplied (replaces %s)"
+ (file-name-nondirectory rngalt-current-schema-file-name)
+ (file-name-nondirectory rng-current-schema-file-name))
+ t))
+ (rngalt-set-validation-header (nth 2 rngalt-validation-header)))))
+
+;; (defun rngalt-clear-validation-header ()
+;; "Remove XML validation header from current buffer.
+;; For more information see `rngalt-show-validation-header'."
+;; (interactive)
+;; (rngalt-set-validation-header nil)
+;; (rng-auto-set-schema t))
+
+;; FIX-ME: Add edit header?
+
+(defun rngalt-get-validation-header-buffer ()
+ (let ((b (get-buffer " *XML Validation Header*")))
+ (unless b
+ (setq b (get-buffer-create " *XML Validation Header*"))
+ (with-current-buffer b
+ ;;(fundamental-mode)
+ (nxml-mode)))
+ b))
+
+(defun rngalt-get-state-after (start-of-doc)
+ ;; FIX-ME: better buffer name?
+ (let ((statebuf (rngalt-get-validation-header-buffer)))
+ (with-current-buffer statebuf
+ (when rng-validate-mode (rng-validate-mode -1))
+ (erase-buffer)
+ (insert start-of-doc)
+ ;; From rng-get-state
+ (setq rng-match-state nil)
+ (setq nxml-ns-state nil)
+ (setq rng-open-elements nil)
+ ;; From rng-match-init-buffer
+ (setq rng-compile-table nil)
+ (setq rng-ipattern-table nil)
+ (setq rng-last-ipattern-index nil)
+
+ (nxml-mode)
+ (rng-validate-mode 1)
+ (rngalt-validate)
+ (let* ((state (rng-get-state))
+ (cp-state (copy-tree state)))
+ ;;(if (equal state cp-state) (message "(equal state cp-state)=t") (message "(equal state cp-state)=nil"))
+ ;; Fix-me: is the copy-tree necessary here?
+ (list
+ cp-state
+ (rng-locate-schema-file)
+ start-of-doc)))))
+
+(defun rngalt-show-validation-header ()
+ "Show XML validation header used in current buffer.
+The XML validation header is used in `nxhtml-mode' to set a state
+for XML validation at the start of the buffer.
+
+The purpose is to make it possible to use `nxml-mode' completion
+in buffers where you do not actually have a full XML file. This
+could for example be a buffer with PHP code or a buffer with a
+blog entry.
+
+More techhnical info: This can be used by any mode derived from
+`nxml-mode'. To use it in other modes than `nxhtml-mode' replace
+`rng-complete' by `rngalt-complete' in `nxml-completion-hook'."
+ (interactive)
+ (unless (derived-mode-p 'nxml-mode)
+ (error "Buffer mode is not an nXml type major mode: %s" major-mode))
+ (rngalt-update-validation-header-buffer)
+ (display-buffer (rngalt-get-validation-header-buffer) t))
+
+(defun rngalt-update-validation-header-buffer ()
+ (let ((vh (nth 2 rngalt-validation-header))
+ (cb (current-buffer)))
+ (with-current-buffer (rngalt-get-validation-header-buffer)
+ (erase-buffer)
+ (if (not vh)
+ (setq header-line-format (concat " No XML validation header in buffer "
+ (buffer-name cb)))
+ (insert vh)
+ (setq header-line-format (concat " XML validation header in buffer "
+ (buffer-name cb)))))))
+
+;; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+
+
+(provide 'rngalt)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; rngalt.el ends here