]> code.delx.au - gnu-emacs/blobdiff - lisp/nxml/nxml-mode.el
Merge from mainline.
[gnu-emacs] / lisp / nxml / nxml-mode.el
index ee08fe9b222564cd7009a0a5eb994ef030de86cc..5eb9840a4ca2b6a480457e617c7738b1d1d1bb0a 100644 (file)
@@ -1,41 +1,36 @@
 ;;; nxml-mode.el --- a new XML mode
 
-;; Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2004, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 ;; Author: James Clark
 ;; Keywords: XML
 
-;; 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 of
-;; the License, or (at your option) any later version.
+;; This file is part of GNU Emacs.
 
-;; 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.
+;; 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.
 
-;; You should have received a copy of the GNU General Public
-;; License along with this program; if not, write to the Free
-;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-;; MA 02111-1307 USA
+;; 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.
 
-;;; Commentary:
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
-;; To use this include rng-auto.el in your .emacs.
+;;; Commentary:
 
 ;; See nxml-rap.el for description of parsing strategy.
 
-;; The font locking here is independent of font-lock.el.  We want to
-;; do more sophisticated handling of changes and we want to use the
-;; same xmltok rather than regexps for parsing so that we parse
-;; consistently and correctly.
-
 ;;; Code:
 
 (when (featurep 'mucs)
   (error "nxml-mode is not compatible with Mule-UCS"))
 
+(eval-when-compile (require 'cl))      ; for assert
+
 (require 'xmltok)
 (require 'nxml-enc)
 (require 'nxml-glyph)
 (require 'nxml-rap)
 (require 'nxml-outln)
 
+(declare-function rng-nxml-mode-init "rng-nxml")
+(declare-function nxml-enable-unicode-char-name-sets "nxml-uchnm")
+
 ;;; Customization
 
 (defgroup nxml nil
-  "New XML editing mode"
-  :group 'languages
-  :group 'wp)
+  "New XML editing mode."
+  :group 'languages)
 
-(defgroup nxml-highlighting-faces nil
+(defgroup nxml-faces nil
   "Faces for XML syntax highlighting."
-  :group 'nxml
-  :group 'font-lock-highlighting-faces)
-
-(defcustom nxml-syntax-highlight-flag t
-  "*Non-nil means nxml-mode should perform syntax highlighting."
-  :group 'nxml
-  :type 'boolean)
+  :group 'nxml)
 
 (defcustom nxml-char-ref-display-glyph-flag t
   "*Non-nil means display glyph following character reference.
-The glyph is displayed in `nxml-glyph-face'.  The hook
+The glyph is displayed in face `nxml-glyph'.  The hook
 `nxml-glyph-set-hook' can be used to customize for which characters
 glyphs are displayed."
   :group 'nxml
@@ -93,20 +84,18 @@ nothing else other than that start-tag."
 
 (defcustom nxml-attribute-indent 4
   "*Indentation for the attributes of an element relative to the start-tag.
-This only applies when the first attribute of a tag starts a line. In other
-cases, the first attribute on one line is indented the same as the first
-attribute on the previous line."
+This only applies when the first attribute of a tag starts a line.
+In other cases, the first attribute on one line is indented the same
+as the first attribute on the previous line."
   :group 'nxml
   :type 'integer)
 
-(defvar nxml-fontify-chunk-size 500)
-
 (defcustom nxml-bind-meta-tab-to-complete-flag (not window-system)
   "*Non-nil means bind M-TAB in `nxml-mode-map' to `nxml-complete'.
 C-return will be bound to `nxml-complete' in any case.
 M-TAB gets swallowed by many window systems/managers, and
 `documentation' will show M-TAB rather than C-return as the
-binding `rng-complete' when both are bound.  So it's better
+binding for `nxml-complete' when both are bound.  So it's better
 to bind M-TAB only when it will work."
   :group 'nxml
   :set (lambda (sym flag)
@@ -134,7 +123,7 @@ and when the encoding declaration specifies `UTF-16'."
 
 (defcustom nxml-default-buffer-file-coding-system nil
   "*Default value for `buffer-file-coding-system' for a buffer for a new file.
-Nil means use the default value of `buffer-file-coding-system' as normal.
+A value of nil means use the default value of `buffer-file-coding-system' as normal.
 A buffer's `buffer-file-coding-system' affects what \\[nxml-insert-xml-declaration] inserts."
   :group 'nxml
   :type 'coding-system)
@@ -145,229 +134,201 @@ The XML declaration is inserted using `nxml-insert-xml-declaration'."
   :group 'nxml
   :type 'boolean)
 
-;; The following are the colors we use with a light background.
-;; The two blues have the same hue but contrasting saturation/value.
-;; The hue of the green is 120 degrees different from that of the
-;; blue.  The red used for highlighting errors is 120 degrees
-;; different again.  We use the light blue only for refs and
-;; delimiters, since these are short (long stretches in a light color
-;; would be too hard to read).  The dark blue is closest to black
-;; (which we use by default for text), so we use it for attribute
-;; values, which are similar to text.
-
-(defconst nxml-light-blue-color "#9292C9") ; hue 240
-(defconst nxml-dark-blue-color "#3A3A7B") ; hue 240
-(defconst nxml-green-color "#257A25") ; hue 120
-
-;; Similar principles apply with a dark background.  However,
-;; we switch green and blue, because darker blues are very hard to
-;; read (for me anyway) on a dark background.
-
-(defconst nxml-sky-blue-color "#ACACFC") ; hue 240
-(defconst nxml-dark-green-color "#00AD00") ; hue 120
-(defconst nxml-light-green-color "#70F170") ; hue 120
-
-(defface nxml-delimited-data-face
-  `((((class color) (background light)) (:foreground ,nxml-dark-blue-color))
-    (((class color) (background dark)) (:foreground ,nxml-light-green-color)))
+(defface nxml-delimited-data
+  '((t (:inherit font-lock-doc-face)))
   "Face used to highlight data enclosed between delimiters.
-By default, this is inherited by `nxml-attribute-value-face'
-and `nxml-processing-instruction-content-face'."
-  :group 'nxml-highlighting-faces)
+This is not used directly, but only via inheritance by other faces."
+  :group 'nxml-faces)
 
-(defface nxml-name-face
-  `((((class color) (background light)) (:foreground ,nxml-green-color))
-    (((class color) (background dark)) (:foreground ,nxml-sky-blue-color)))
+(defface nxml-name
+  '((t (:inherit font-lock-builtin-face)))
   "Face used to highlight various names.
 This includes element and attribute names, processing
 instruction targets and the CDATA keyword in a CDATA section.
 This is not used directly, but only via inheritance by other faces."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-ref-face
-  `((((class color) (background light)) (:foreground ,nxml-light-blue-color))
-    (((class color) (background dark)) (:foreground ,nxml-dark-green-color)))
+(defface nxml-ref
+  '((t (:inherit font-lock-constant-face)))
   "Face used to highlight character and entity references.
 This is not used directly, but only via inheritance by other faces."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-delimiter-face
-  `((((class color) (background light)) (:foreground ,nxml-light-blue-color))
-    (((class color) (background dark)) (:foreground ,nxml-dark-green-color))
-    (t (:bold t)))
+(defface nxml-delimiter
+  nil
   "Face used to highlight delimiters.
 This is not used directly, but only via inheritance by other faces."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-text-face
+(defface nxml-text
   nil
   "Face used to highlight text."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-comment-content-face
-  '((t (:italic t)))
+(defface nxml-comment-content
+  '((t (:inherit font-lock-comment-face)))
   "Face used to highlight the content of comments."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-comment-delimiter-face
-  '((t (:inherit nxml-delimiter-face)))
+(defface nxml-comment-delimiter
+  '((t (:inherit font-lock-comment-delimiter-face)))
   "Face used for the delimiters of comments, i.e <!-- and -->."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-processing-instruction-delimiter-face
-  '((t (:inherit nxml-delimiter-face)))
+(defface nxml-processing-instruction-delimiter
+  '((t (:inherit nxml-delimiter)))
   "Face used for the delimiters of processing instructions, i.e <? and ?>."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-processing-instruction-target-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-processing-instruction-target
+  '((t (:inherit font-lock-keyword-face)))
   "Face used for the target of processing instructions."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-processing-instruction-content-face
-  '((t (:inherit nxml-delimited-data-face)))
+(defface nxml-processing-instruction-content
+  '((t (:inherit nxml-delimited-data)))
   "Face used for the content of processing instructions."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-cdata-section-delimiter-face
-  '((t (:inherit nxml-delimiter-face)))
+(defface nxml-cdata-section-delimiter
+  '((t (:inherit nxml-delimiter)))
   "Face used for the delimiters of CDATA sections, i.e <![, [, and ]]>."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-cdata-section-CDATA-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-cdata-section-CDATA
+  '((t (:inherit nxml-name)))
   "Face used for the CDATA keyword in CDATA sections."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-cdata-section-content-face
-  '((t (:inherit nxml-text-face)))
+(defface nxml-cdata-section-content
+  '((t (:inherit nxml-text)))
   "Face used for the content of CDATA sections."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-char-ref-number-face
-  '((t (:inherit nxml-ref-face)))
+(defface nxml-char-ref-number
+  '((t (:inherit nxml-ref)))
   "Face used for the number in character references.
 This includes ths `x' in hex references."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-char-ref-delimiter-face
-  '((t (:inherit nxml-ref-face)))
+(defface nxml-char-ref-delimiter
+  '((t (:inherit nxml-ref)))
   "Face used for the delimiters of character references, i.e &# and ;."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-entity-ref-name-face
-  '((t (:inherit nxml-ref-face)))
+(defface nxml-entity-ref-name
+  '((t (:inherit nxml-ref)))
   "Face used for the entity name in general entity references."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-entity-ref-delimiter-face
-  '((t (:inherit nxml-ref-face)))
+(defface nxml-entity-ref-delimiter
+  '((t (:inherit nxml-ref)))
   "Face used for the delimiters of entity references, i.e & and ;."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-tag-delimiter-face
-  '((t (:inherit nxml-delimiter-face)))
+(defface nxml-tag-delimiter
+  '((t (:inherit nxml-delimiter)))
   "Face used for the angle brackets delimiting tags.
-`nxml-tag-slash-face' is used for slashes."
-  :group 'nxml-highlighting-faces)
+`nxml-tag-slash' is used for slashes."
+  :group 'nxml-faces)
 
-(defface nxml-tag-slash-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-tag-slash
+  '((t (:inherit nxml-tag-delimiter)))
   "Face used for slashes in tags, both in end-tags and empty-elements."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-element-prefix-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-element-prefix
+  '((t (:inherit nxml-name)))
   "Face used for the prefix of elements."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-element-colon-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-element-colon
+  nil
   "Face used for the colon in element names."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-element-local-name-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-element-local-name
+  '((t (:inherit font-lock-function-name-face)))
   "Face used for the local name of elements."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-attribute-prefix-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-attribute-prefix
+  '((t (:inherit nxml-name)))
   "Face used for the prefix of attributes."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-attribute-colon-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-attribute-colon
+  '((t (:inherit nxml-delimiter)))
   "Face used for the colon in attribute names."
-  :group 'nxml-highlighting-faces)
-  
-(defface nxml-attribute-local-name-face
-  '((t (:inherit nxml-name-face)))
+  :group 'nxml-faces)
+
+(defface nxml-attribute-local-name
+  '((t (:inherit font-lock-variable-name-face)))
   "Face used for the local name of attributes."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-namespace-attribute-xmlns-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-namespace-attribute-xmlns
+  '((t (:inherit nxml-attribute-prefix)))
   "Face used for `xmlns' in namespace attributes."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-namespace-attribute-colon-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-namespace-attribute-colon
+  '((t (:inherit nxml-attribute-colon)))
   "Face used for the colon in namespace attributes."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-namespace-attribute-prefix-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-namespace-attribute-prefix
+  '((t (:inherit nxml-attribute-local-name)))
   "Face used for the prefix declared in namespace attributes."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-attribute-value-face
-  '((t (:inherit nxml-delimited-data-face)))
+(defface nxml-attribute-value
+  '((t (:inherit font-lock-string-face)))
   "Face used for the value of attributes."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-attribute-value-delimiter-face
-  '((t (:inherit nxml-delimiter-face)))
+(defface nxml-attribute-value-delimiter
+  '((t (:inherit nxml-attribute-value)))
   "Face used for the delimiters of attribute values."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-namespace-attribute-value-face
-  '((t (:inherit nxml-attribute-value-face)))
+(defface nxml-namespace-attribute-value
+  '((t (:inherit nxml-attribute-value)))
   "Face used for the value of namespace attributes."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-namespace-attribute-value-delimiter-face
-  '((t (:inherit nxml-attribute-value-delimiter-face)))
+(defface nxml-namespace-attribute-value-delimiter
+  '((t (:inherit nxml-attribute-value-delimiter)))
   "Face used for the delimiters of namespace attribute values."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-prolog-literal-delimiter-face
-  '((t (:inherit nxml-delimiter-face)))
+(defface nxml-prolog-literal-delimiter
+  '((t (:inherit nxml-delimited-data)))
   "Face used for the delimiters of literals in the prolog."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-prolog-literal-content-face
-  '((t (:inherit nxml-delimited-data-face)))
+(defface nxml-prolog-literal-content
+  '((t (:inherit nxml-delimited-data)))
   "Face used for the content of literals in the prolog."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-prolog-keyword-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-prolog-keyword
+  '((t (:inherit font-lock-keyword-face)))
   "Face used for keywords in the prolog."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-markup-declaration-delimiter-face
-  '((t (:inherit nxml-delimiter-face)))
+(defface nxml-markup-declaration-delimiter
+  '((t (:inherit nxml-delimiter)))
   "Face used for the delimiters of markup declarations in the prolog.
 The delimiters are <! and >."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-hash-face
-  '((t (:inherit nxml-name-face)))
+(defface nxml-hash
+  '((t (:inherit nxml-name)))
   "Face used for # before a name in the prolog."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
-(defface nxml-glyph-face
+(defface nxml-glyph
   '((((type x))
      (:family
       "misc-fixed"
@@ -376,7 +337,7 @@ The delimiters are <! and >."
       :foreground
       "black"
       :weight
-      normal 
+      normal
       :slant
       normal))
     (t
@@ -385,18 +346,14 @@ The delimiters are <! and >."
       :foreground
       "black"
       :weight
-      normal 
+      normal
       :slant
       normal)))
   "Face used for glyph for char references."
-  :group 'nxml-highlighting-faces)
+  :group 'nxml-faces)
 
 ;;; Global variables
 
-;; This is initialized in rng-auto.el.
-(defvar nxml-version nil
-  "*The version of nxml-mode that is being used.")
-
 (defvar nxml-prolog-regions nil
   "List of regions in the prolog to be fontified.
 See the function `xmltok-forward-prolog' for more information.")
@@ -404,7 +361,7 @@ See the function `xmltok-forward-prolog' for more information.")
 
 (defvar nxml-last-fontify-end nil
   "Position where fontification last ended.
-Nil if the buffer changed since the last fontification.")
+It is nil if the buffer changed since the last fontification.")
 (make-variable-buffer-local 'nxml-last-fontify-end)
 
 (defvar nxml-degraded nil
@@ -457,25 +414,19 @@ reference.")
     (define-key map "\C-c\C-o" nxml-outline-prefix-map)
     (define-key map [S-mouse-2] 'nxml-mouse-hide-direct-text-content)
     (define-key map "/" 'nxml-electric-slash)
-    (define-key map [C-return] 'nxml-complete) 
+    (define-key map [C-return] 'nxml-complete)
     (when nxml-bind-meta-tab-to-complete-flag
       (define-key map "\M-\t" 'nxml-complete))
     map)
   "Keymap for nxml-mode.")
 
+(defvar nxml-font-lock-keywords
+  '(nxml-fontify-matcher)
+  "Default font lock keywords for nxml-mode.")
+
 (defsubst nxml-set-face (start end face)
   (when (and face (< start end))
-    (put-text-property start end 'face face)))
-
-(defun nxml-clear-face (start end)
-  (remove-text-properties start end '(face nil))
-  (nxml-clear-char-ref-extra-display start end))
-
-(defsubst nxml-set-fontified (start end)
-  (put-text-property start end 'fontified t))
-
-(defsubst nxml-clear-fontified (start end)
-  (remove-text-properties start end '(fontified nil)))
+    (font-lock-append-text-property start end 'face face)))
 
 ;;;###autoload
 (defun nxml-mode ()
@@ -484,12 +435,9 @@ reference.")
   ;; not mnemonic.
   "Major mode for editing XML.
 
-Syntax highlighting is performed unless the variable
-`nxml-syntax-highlight-flag' is nil.
-
 \\[nxml-finish-element] finishes the current element by inserting an end-tag.
 C-c C-i closes a start-tag with `>' and then inserts a balancing end-tag
-leaving point between the start-tag and end-tag. 
+leaving point between the start-tag and end-tag.
 \\[nxml-balanced-close-start-tag-block] is similar but for block rather than inline elements:
 the start-tag, point, and end-tag are all left on separate lines.
 If `nxml-slash-auto-complete-flag' is non-nil, then inserting a `</'
@@ -509,17 +457,17 @@ instead of C-c.
 Validation is provided by the related minor-mode `rng-validate-mode'.
 This also makes completion schema- and context- sensitive.  Element
 names, attribute names, attribute values and namespace URIs can all be
-completed. By default, `rng-validate-mode' is automatically enabled by
-`rng-nxml-mode-init' which is normally added to `nxml-mode-hook'. You
-can toggle it using \\[rng-validate-mode].
+completed. By default, `rng-validate-mode' is automatically enabled.
+You can toggle it using \\[rng-validate-mode] or change the default by
+customizing `rng-nxml-auto-validate-flag'.
 
 \\[indent-for-tab-command] indents the current line appropriately.
 This can be customized using the variable `nxml-child-indent'
 and the variable `nxml-attribute-indent'.
 
 \\[nxml-insert-named-char] inserts a character reference using
-the character's name (by default, the Unicode name). \\[universal-argument] \\[nxml-insert-named-char]
-inserts the character directly.
+the character's name (by default, the Unicode name).
+\\[universal-argument] \\[nxml-insert-named-char] inserts the character directly.
 
 The Emacs commands that normally operate on balanced expressions will
 operate on XML markup items.  Thus \\[forward-sexp] will move forward
@@ -539,6 +487,7 @@ Many aspects this mode can be customized using
   (kill-all-local-variables)
   (setq major-mode 'nxml-mode)
   (setq mode-name "nXML")
+  (set (make-local-variable 'mode-line-process) '((nxml-degraded "/degraded")))
   ;; We'll determine the fill prefix ourselves
   (make-local-variable 'adaptive-fill-mode)
   (setq adaptive-fill-mode nil)
@@ -570,22 +519,54 @@ Many aspects this mode can be customized using
       (nxml-clear-dependent-regions (point-min) (point-max))
       (setq nxml-scan-end (copy-marker (point-min) nil))
       (nxml-with-unmodifying-text-property-changes
-       (when nxml-syntax-highlight-flag
-         (nxml-clear-fontified (point-min) (point-max)))
-       (nxml-clear-inside (point-min) (point-max))
+        (nxml-clear-inside (point-min) (point-max))
        (nxml-with-invisible-motion
          (nxml-scan-prolog)))))
-  (when nxml-syntax-highlight-flag
-    (add-hook 'fontification-functions 'nxml-fontify nil t))
   (add-hook 'after-change-functions 'nxml-after-change nil t)
-  (add-hook 'write-contents-hooks 'nxml-prepare-to-save)
+  (add-hook 'change-major-mode-hook 'nxml-cleanup nil t)
+
+  ;; Emacs 23 handles the encoding attribute on the xml declaration
+  ;; transparently to nxml-mode, so there is no longer a need for the below
+  ;; hook. The hook also had the drawback of overriding explicit user
+  ;; instruction to save as some encoding other than utf-8.
+;;;   (add-hook 'write-contents-hooks 'nxml-prepare-to-save)
   (when (not (and (buffer-file-name) (file-exists-p (buffer-file-name))))
     (when (and nxml-default-buffer-file-coding-system
               (not (local-variable-p 'buffer-file-coding-system)))
       (setq buffer-file-coding-system nxml-default-buffer-file-coding-system))
     (when nxml-auto-insert-xml-declaration-flag
       (nxml-insert-xml-declaration)))
-  (run-hooks 'nxml-mode-hook))
+
+  (setq font-lock-defaults
+        '(nxml-font-lock-keywords
+          t    ; keywords-only; we highlight comments and strings here
+          nil  ; font-lock-keywords-case-fold-search. XML is case sensitive
+          nil  ; no special syntax table
+          nil  ; no automatic syntactic fontification
+          (font-lock-extend-after-change-region-function
+           . nxml-extend-after-change-region)
+          (font-lock-extend-region-functions . (nxml-extend-region))
+          (jit-lock-contextually . t)
+          (font-lock-unfontify-region-function . nxml-unfontify-region)))
+
+  (rng-nxml-mode-init)
+  (nxml-enable-unicode-char-name-sets)
+  (run-mode-hooks 'nxml-mode-hook))
+
+(defun nxml-cleanup ()
+  "Clean up after nxml-mode."
+  ;; Disable associated minor modes.
+  (rng-validate-mode -1)
+  ;; Clean up fontification.
+  (save-excursion
+    (widen)
+    (let ((inhibit-read-only t)
+         (buffer-undo-list t)
+         (modified (buffer-modified-p)))
+      (nxml-with-invisible-motion
+       (remove-text-properties (point-min) (point-max) '(face)))
+      (set-buffer-modified-p modified)))
+  (remove-hook 'change-major-mode-hook 'nxml-cleanup t))
 
 (defun nxml-degrade (context err)
   (message "Internal nXML mode error in %s (%s), degrading"
@@ -598,85 +579,73 @@ Many aspects this mode can be customized using
     (save-restriction
       (widen)
       (nxml-with-unmodifying-text-property-changes
-       (nxml-clear-face (point-min) (point-max))
-       (nxml-set-fontified (point-min) (point-max))
-       (nxml-clear-inside (point-min) (point-max)))
-      (setq mode-name "nXML/degraded"))))
+       (nxml-clear-inside (point-min) (point-max))))))
 
 ;;; Change management
 
+(defun nxml-debug-region (start end)
+  (interactive "r")
+  (let ((font-lock-beg start)
+        (font-lock-end end))
+    (nxml-extend-region)
+    (goto-char font-lock-beg)
+    (set-mark font-lock-end)))
+
 (defun nxml-after-change (start end pre-change-length)
-  ;; Work around bug in insert-file-contents.
-  (when (> end (1+ (buffer-size)))
-    (setq start 1)
-    (setq end (1+ (buffer-size))))
-  (unless nxml-degraded
-    (condition-case err
-       (save-excursion
-         (save-restriction
-           (widen)
-           (save-match-data
-             (nxml-with-invisible-motion
-               (nxml-with-unmodifying-text-property-changes
-                 (nxml-after-change1 start end pre-change-length))))))
-      (error
-       (nxml-degrade 'nxml-after-change err)))))
+  ; In font-lock mode, nxml-after-change1 is called via
+  ; nxml-extend-after-change-region instead so that the updated
+  ; book-keeping information is available for fontification.
+  (unless (or font-lock-mode nxml-degraded)
+    (nxml-with-degradation-on-error 'nxml-after-change
+        (save-excursion
+          (save-restriction
+            (widen)
+            (save-match-data
+              (nxml-with-invisible-motion
+                (nxml-with-unmodifying-text-property-changes
+                  (nxml-after-change1
+                   start end pre-change-length)))))))))
 
 (defun nxml-after-change1 (start end pre-change-length)
-  (setq nxml-last-fontify-end nil)
+  "After-change bookkeeping.
+Returns a cons cell containing a possibly-enlarged change region.
+You must call `nxml-extend-region' on this expanded region to obtain
+the full extent of the area needing refontification.
+
+For bookkeeping, call this function even when fontification is
+disabled."
   (let ((pre-change-end (+ start pre-change-length)))
     (setq start
          (nxml-adjust-start-for-dependent-regions start
                                                   end
                                                   pre-change-length))
+    ;; If the prolog might have changed, rescan the prolog
     (when (<= start
-             ;; Add 2 so as to include the < and following char
-             ;; that start the instance, since changing these
-             ;; can change where the prolog ends.
+             ;; Add 2 so as to include the < and following char that
+             ;; start the instance (document element), since changing
+             ;; these can change where the prolog ends.
              (+ nxml-prolog-end 2))
-      ;; end must be extended to at least the end of the old prolog
+      ;; end must be extended to at least the end of the old prolog in
+      ;; case the new prolog is shorter
       (when (< pre-change-end nxml-prolog-end)
        (setq end
              ;; don't let end get out of range even if pre-change-length
              ;; is bogus
              (min (point-max)
                   (+ end (- nxml-prolog-end pre-change-end)))))
-      (nxml-scan-prolog)))
-  (cond ((<= end nxml-prolog-end)
-        (setq end nxml-prolog-end)
-        (goto-char start)
-        ;; This is so that Emacs redisplay works
-        (setq start (line-beginning-position)))
-       ((and (<= start nxml-scan-end)
-             (> start (point-min))
-             (nxml-get-inside (1- start)))
-        ;; The closing delimiter might have been removed.
-        ;; So we may need to redisplay from the beginning
-        ;; of the token.
-        (goto-char (1- start))
-        (nxml-move-outside-backwards)
-        ;; This is so that Emacs redisplay works
-        (setq start (line-beginning-position))
-        (setq end (max (nxml-scan-after-change (point) end)
-                       end)))
-       (t
-        (goto-char start)
-        ;; This is both for redisplay and to move back
-        ;; past any incomplete opening delimiters
-        (setq start (line-beginning-position))
-        (setq end (max (nxml-scan-after-change start end)
-                       end))))
-  (when nxml-syntax-highlight-flag
-    (when (>= start end)
-      ;; Must clear at least one char so as to trigger redisplay.
-      (cond ((< start (point-max))
-            (setq end (1+ start)))
-           (t
-            (setq end (point-max))
-            (goto-char end)
-            (setq start (line-beginning-position)))))
-    (nxml-clear-fontified start end)))
-  
+      (nxml-scan-prolog)
+      (setq start (point-min))))
+
+  (when (> end nxml-prolog-end)
+    (goto-char start)
+    (nxml-move-tag-backwards (point-min))
+    (setq start (point))
+    (setq end (max (nxml-scan-after-change start end)
+                   end)))
+
+  (nxml-debug-change "nxml-after-change1" start end)
+  (cons start end))
+
 ;;; Encodings
 
 (defun nxml-insert-xml-declaration ()
@@ -829,7 +798,7 @@ The XML declaration will declare an encoding depending on the buffer's
          (setq suitable-coding-systems (cdr suitable-coding-systems))))
       ret)))
 
-(defun nxml-choose-utf-coding-system ()             
+(defun nxml-choose-utf-coding-system ()
   (let ((cur (and (local-variable-p 'buffer-file-coding-system)
                  buffer-file-coding-system
                  (coding-system-base buffer-file-coding-system))))
@@ -862,51 +831,99 @@ The XML declaration will declare an encoding depending on the buffer's
 
 ;;; Fontification
 
-(defun nxml-fontify (start)
-  (condition-case err
-      (save-excursion
-       (save-restriction
-         (widen)
-         (save-match-data
-           (nxml-with-invisible-motion
-             (nxml-with-unmodifying-text-property-changes
-               (if (or nxml-degraded
-                       ;; just in case we get called in the wrong buffer
-                       (not nxml-prolog-end))
-                   (nxml-set-fontified start (point-max))
-                 (nxml-fontify1 start)))))))
-    (error
-     (nxml-degrade 'nxml-fontify err))))
-
-(defun nxml-fontify1 (start)
-  (cond ((< start nxml-prolog-end)
-        (nxml-fontify-prolog)
-        (nxml-set-fontified (point-min)
-                            nxml-prolog-end))
-       (t
-        (goto-char start)
-        (when (not (eq nxml-last-fontify-end start))
-          (when (not (equal (char-after) ?\<))
-            (search-backward "<" nxml-prolog-end t))
-          (nxml-ensure-scan-up-to-date)
-          (nxml-move-outside-backwards))
-        (let ((start (point)))
-          (nxml-do-fontify (min (point-max)
-                                (+ start nxml-fontify-chunk-size)))
-          (setq nxml-last-fontify-end (point))
-          (nxml-set-fontified start nxml-last-fontify-end)))))
-
-(defun nxml-fontify-buffer ()
-  (interactive)
-  (save-excursion
-    (save-restriction
-      (widen)
-      (nxml-with-invisible-motion
-       (goto-char (point-min))
-       (nxml-with-unmodifying-text-property-changes
-         (nxml-fontify-prolog)
-         (goto-char nxml-prolog-end)
-         (nxml-do-fontify))))))
+(defun nxml-unfontify-region (start end)
+  (font-lock-default-unfontify-region start end)
+  (nxml-clear-char-ref-extra-display start end))
+
+(defvar font-lock-beg) (defvar font-lock-end)
+(defun nxml-extend-region ()
+  "Extend the region to hold the minimum area we can fontify with nXML.
+Called with `font-lock-beg' and `font-lock-end' dynamically bound."
+  (let ((start font-lock-beg)
+        (end font-lock-end))
+
+    (nxml-debug-change "nxml-extend-region(input)" start end)
+
+    (when (< start nxml-prolog-end)
+      (setq start (point-min)))
+
+    (cond ((<= end nxml-prolog-end)
+           (setq end nxml-prolog-end))
+
+          (t
+           (goto-char start)
+           ;; some font-lock backends (like Emacs 22 jit-lock) snap
+           ;; the region to the beginning of the line no matter what
+           ;; we say here. To mitigate the resulting excess
+           ;; fontification, ignore leading whitespace.
+           (skip-syntax-forward " ")
+
+           ;; find the beginning of the previous tag
+           (when (not (equal (char-after) ?\<))
+             (search-backward "<" nxml-prolog-end t))
+           (nxml-ensure-scan-up-to-date)
+           (nxml-move-outside-backwards)
+           (setq start (point))
+
+           (while (< (point) end)
+             (nxml-tokenize-forward))
+
+           (setq end (point))))
+
+    (when (or (< start font-lock-beg)
+              (> end font-lock-end))
+      (setq font-lock-beg start
+            font-lock-end end)
+      (nxml-debug-change "nxml-extend-region" start end)
+      t)))
+
+(defun nxml-extend-after-change-region (start end pre-change-length)
+  (unless nxml-degraded
+    (setq nxml-last-fontify-end nil)
+    (let ((region (nxml-with-degradation-on-error
+                  'nxml-extend-after-change-region
+                  (save-excursion
+                    (save-restriction
+                      (widen)
+                      (save-match-data
+                        (nxml-with-invisible-motion
+                          (nxml-with-unmodifying-text-property-changes
+                            (nxml-extend-after-change-region1
+                             start end pre-change-length)))))))))
+      (if (consp region) region))))
+
+(defun nxml-extend-after-change-region1 (start end pre-change-length)
+  (let* ((region (nxml-after-change1 start end pre-change-length))
+         (font-lock-beg (car region))
+         (font-lock-end (cdr region)))
+
+    (nxml-extend-region)
+    (cons font-lock-beg font-lock-end)))
+
+(defun nxml-fontify-matcher (bound)
+  "Called as font-lock keyword matcher."
+
+  (unless nxml-degraded
+    (nxml-debug-change "nxml-fontify-matcher" (point) bound)
+
+    (when (< (point) nxml-prolog-end)
+      ;; prolog needs to be fontified in one go, and
+      ;; nxml-extend-region makes sure we start at BOB.
+      (assert (bobp))
+      (nxml-fontify-prolog)
+      (goto-char nxml-prolog-end))
+
+    (let (xmltok-dependent-regions
+          xmltok-errors)
+      (while (and (nxml-tokenize-forward)
+                  (<= (point) bound)) ; intervals are open-ended
+        (nxml-apply-fontify-rule)))
+
+    (setq nxml-last-fontify-end (point)))
+
+  ;; Since we did the fontification internally, tell font-lock to not
+  ;; do anything itself.
+  nil)
 
 (defun nxml-fontify-prolog ()
   "Fontify the prolog.
@@ -914,7 +931,6 @@ The buffer is assumed to be prepared for fontification.
 This does not set the fontified property, but it does clear
 faces appropriately."
   (let ((regions nxml-prolog-regions))
-    (nxml-clear-face (point-min) nxml-prolog-end)
     (while regions
       (let ((region (car regions)))
        (nxml-apply-fontify-rule (aref region 0)
@@ -922,159 +938,148 @@ faces appropriately."
                                 (aref region 2)))
       (setq regions (cdr regions)))))
 
-(defun nxml-do-fontify (&optional bound)
-  "Fontify at least as far as bound.
-Leave point after last fontified position."
-  (unless bound (setq bound (point-max)))
-  (let (xmltok-dependent-regions
-       xmltok-errors)
-    (while (and (< (point) bound)
-               (nxml-tokenize-forward))
-      (nxml-clear-face xmltok-start (point))
-      (nxml-apply-fontify-rule))))
-
 ;; Vectors identify a substring of the token to be highlighted in some face.
 
 ;; Token types returned by xmltok-forward.
 
 (put 'start-tag
      'nxml-fontify-rule
-     '([nil 1 nxml-tag-delimiter-face]
-       [-1 nil nxml-tag-delimiter-face]
+     '([nil 1 nxml-tag-delimiter]
+       [-1 nil nxml-tag-delimiter]
        (element-qname . 1)
        attributes))
 
 (put 'partial-start-tag
      'nxml-fontify-rule
-     '([nil 1 nxml-tag-delimiter-face]
+     '([nil 1 nxml-tag-delimiter]
        (element-qname . 1)
        attributes))
 
 (put 'end-tag
      'nxml-fontify-rule
-     '([nil 1 nxml-tag-delimiter-face]
-       [1 2 nxml-tag-slash-face]
-       [-1 nil nxml-tag-delimiter-face]
+     '([nil 1 nxml-tag-delimiter]
+       [1 2 nxml-tag-slash]
+       [-1 nil nxml-tag-delimiter]
        (element-qname . 2)))
 
 (put 'partial-end-tag
      'nxml-fontify-rule
-     '([nil 1 nxml-tag-delimiter-face]
-       [1 2 nxml-tag-slash-face]
+     '([nil 1 nxml-tag-delimiter]
+       [1 2 nxml-tag-slash]
        (element-qname . 2)))
 
 (put 'empty-element
      'nxml-fontify-rule
-     '([nil 1 nxml-tag-delimiter-face]
-       [-2 -1 nxml-tag-slash-face]
-       [-1 nil nxml-tag-delimiter-face]
+     '([nil 1 nxml-tag-delimiter]
+       [-2 -1 nxml-tag-slash]
+       [-1 nil nxml-tag-delimiter]
        (element-qname . 1)
        attributes))
 
 (put 'partial-empty-element
      'nxml-fontify-rule
-     '([nil 1 nxml-tag-delimiter-face]
-       [-1 nil nxml-tag-slash-face]
+     '([nil 1 nxml-tag-delimiter]
+       [-1 nil nxml-tag-slash]
        (element-qname . 1)
        attributes))
 
 (put 'char-ref
      'nxml-fontify-rule
-     '([nil 2 nxml-char-ref-delimiter-face]
-       [2 -1 nxml-char-ref-number-face]
-       [-1 nil nxml-char-ref-delimiter-face]
+     '([nil 2 nxml-char-ref-delimiter]
+       [2 -1 nxml-char-ref-number]
+       [-1 nil nxml-char-ref-delimiter]
        char-ref))
 
 (put 'entity-ref
      'nxml-fontify-rule
-     '([nil 1 nxml-entity-ref-delimiter-face]
-       [1 -1 nxml-entity-ref-name-face]
-       [-1 nil nxml-entity-ref-delimiter-face]))
+     '([nil 1 nxml-entity-ref-delimiter]
+       [1 -1 nxml-entity-ref-name]
+       [-1 nil nxml-entity-ref-delimiter]))
 
 (put 'comment
      'nxml-fontify-rule
-     '([nil 4 nxml-comment-delimiter-face]
-       [4 -3 nxml-comment-content-face]
-       [-3 nil nxml-comment-delimiter-face]))
+     '([nil 4 nxml-comment-delimiter]
+       [4 -3 nxml-comment-content]
+       [-3 nil nxml-comment-delimiter]))
 
 (put 'processing-instruction
      'nxml-fontify-rule
-     '([nil 2 nxml-processing-instruction-delimiter-face]
-       [-2 nil nxml-processing-instruction-delimiter-face]
+     '([nil 2 nxml-processing-instruction-delimiter]
+       [-2 nil nxml-processing-instruction-delimiter]
        processing-instruction-content))
 
 (put 'cdata-section
      'nxml-fontify-rule
-     '([nil 3 nxml-cdata-section-delimiter-face] ; <![
-       [3 8 nxml-cdata-section-CDATA-face] ; CDATA
-       [8 9 nxml-cdata-section-delimiter-face] ; [
-       [9 -3 nxml-cdata-section-content-face] ; ]]>
-       [-3 nil nxml-cdata-section-delimiter-face]))
+     '([nil 3 nxml-cdata-section-delimiter] ; <![
+       [3 8 nxml-cdata-section-CDATA] ; CDATA
+       [8 9 nxml-cdata-section-delimiter] ; [
+       [9 -3 nxml-cdata-section-content] ; ]]>
+       [-3 nil nxml-cdata-section-delimiter]))
 
 (put 'data
      'nxml-fontify-rule
-     '([nil nil nxml-text-face]))
+     '([nil nil nxml-text]))
 
 ;; Prolog region types in list returned by xmltok-forward-prolog.
 
 (put 'xml-declaration
      'nxml-fontify-rule
-     '([nil 2 nxml-processing-instruction-delimiter-face]
-       [2 5 nxml-processing-instruction-target-face]
-       [-2 nil nxml-processing-instruction-delimiter-face]))
+     '([nil 2 nxml-processing-instruction-delimiter]
+       [2 5 nxml-processing-instruction-target]
+       [-2 nil nxml-processing-instruction-delimiter]))
 
 (put 'xml-declaration-attribute-name
      'nxml-fontify-rule
-     '([nil nil nxml-attribute-local-name-face]))
+     '([nil nil nxml-attribute-local-name]))
 
 (put 'xml-declaration-attribute-value
      'nxml-fontify-rule
-     '([nil 1 nxml-attribute-value-delimiter-face]
-       [1 -1 nxml-attribute-value-face]
-       [-1 nil nxml-attribute-value-delimiter-face]))
+     '([nil 1 nxml-attribute-value-delimiter]
+       [1 -1 nxml-attribute-value]
+       [-1 nil nxml-attribute-value-delimiter]))
 
 (put 'processing-instruction-left
      'nxml-fontify-rule
-     '([nil 2 nxml-processing-instruction-delimiter-face]
-       [2 nil nxml-processing-instruction-target-face]))
+     '([nil 2 nxml-processing-instruction-delimiter]
+       [2 nil nxml-processing-instruction-target]))
 
 (put 'processing-instruction-right
      'nxml-fontify-rule
-     '([nil -2 nxml-processing-instruction-content-face]
-       [-2 nil nxml-processing-instruction-delimiter-face]))
+     '([nil -2 nxml-processing-instruction-content]
+       [-2 nil nxml-processing-instruction-delimiter]))
 
 (put 'literal
      'nxml-fontify-rule
-     '([nil 1 nxml-prolog-literal-delimiter-face]
-       [1 -1 nxml-prolog-literal-content-face]
-       [-1 nil nxml-prolog-literal-delimiter-face]))
+     '([nil 1 nxml-prolog-literal-delimiter]
+       [1 -1 nxml-prolog-literal-content]
+       [-1 nil nxml-prolog-literal-delimiter]))
 
 (put 'keyword
      'nxml-fontify-rule
-     '([nil nil nxml-prolog-keyword-face]))
+     '([nil nil nxml-prolog-keyword]))
 
 (put 'markup-declaration-open
      'nxml-fontify-rule
-     '([0 2 nxml-markup-declaration-delimiter-face]
-       [2 nil nxml-prolog-keyword-face]))
+     '([0 2 nxml-markup-declaration-delimiter]
+       [2 nil nxml-prolog-keyword]))
 
 (put 'markup-declaration-close
      'nxml-fontify-rule
-     '([nil nil nxml-markup-declaration-delimiter-face]))
+     '([nil nil nxml-markup-declaration-delimiter]))
 
 (put 'internal-subset-open
      'nxml-fontify-rule
-     '([nil nil nxml-markup-declaration-delimiter-face]))
+     '([nil nil nxml-markup-declaration-delimiter]))
 
 (put 'internal-subset-close
      'nxml-fontify-rule
-     '([nil 1 nxml-markup-declaration-delimiter-face]
-       [-1 nil nxml-markup-declaration-delimiter-face]))
+     '([nil 1 nxml-markup-declaration-delimiter]
+       [-1 nil nxml-markup-declaration-delimiter]))
 
 (put 'hash-name
      'nxml-fontify-rule
-     '([nil 1 nxml-hash-face]
-       [1 nil nxml-prolog-keyword-face]))
+     '([nil 1 nxml-hash]
+       [1 nil nxml-prolog-keyword]))
 
 (defun nxml-apply-fontify-rule (&optional type start end)
   (let ((rule (get (or type xmltok-type) 'nxml-fontify-rule)))
@@ -1099,21 +1104,21 @@ Leave point after last fontified position."
                 (nxml-fontify-qname (+ start (cdr action))
                                     xmltok-name-colon
                                     xmltok-name-end
-                                    'nxml-element-prefix-face
-                                    'nxml-element-colon-face
-                                    'nxml-element-local-name-face)))
+                                    'nxml-element-prefix
+                                    'nxml-element-colon
+                                    'nxml-element-local-name)))
              ((eq action 'attributes)
               (nxml-fontify-attributes))
              ((eq action 'processing-instruction-content)
               (nxml-set-face (+ start 2)
                              xmltok-name-end
-                             'nxml-processing-instruction-target-face)
+                             'nxml-processing-instruction-target)
               (nxml-set-face (save-excursion
                                (goto-char xmltok-name-end)
                                (skip-chars-forward " \t\r\n")
                                (point))
                              (- end 2)
-                             'nxml-processing-instruction-content-face))
+                             'nxml-processing-instruction-content))
              ((eq action 'char-ref)
               (nxml-char-ref-display-extra start
                                            end
@@ -1136,25 +1141,25 @@ Leave point after last fontified position."
       (nxml-fontify-qname (xmltok-attribute-name-start att)
                          (xmltok-attribute-name-colon att)
                          (xmltok-attribute-name-end att)
-                         'nxml-namespace-attribute-xmlns-face
-                         'nxml-namespace-attribute-colon-face
-                         'nxml-namespace-attribute-prefix-face
-                         'nxml-namespace-attribute-xmlns-face)
+                         'nxml-namespace-attribute-xmlns
+                         'nxml-namespace-attribute-colon
+                         'nxml-namespace-attribute-prefix
+                         'nxml-namespace-attribute-xmlns)
     (nxml-fontify-qname (xmltok-attribute-name-start att)
                        (xmltok-attribute-name-colon att)
                        (xmltok-attribute-name-end att)
-                       'nxml-attribute-prefix-face
-                       'nxml-attribute-colon-face
-                       'nxml-attribute-local-name-face))
+                       'nxml-attribute-prefix
+                       'nxml-attribute-colon
+                       'nxml-attribute-local-name))
   (let ((start (xmltok-attribute-value-start att))
        (end (xmltok-attribute-value-end att))
        (refs (xmltok-attribute-refs att))
        (delimiter-face (if namespace-declaration
-                           'nxml-namespace-attribute-value-delimiter-face
-                         'nxml-attribute-value-delimiter-face))
+                           'nxml-namespace-attribute-value-delimiter
+                         'nxml-attribute-value-delimiter))
        (value-face (if namespace-declaration
-                       'nxml-namespace-attribute-value-face
-                     'nxml-attribute-value-face)))
+                       'nxml-namespace-attribute-value
+                     'nxml-attribute-value)))
     (when start
       (nxml-set-face (1- start) start delimiter-face)
       (nxml-set-face end (1+ end) delimiter-face)
@@ -1248,31 +1253,33 @@ No extra whitespace is inserted."
 
 (defun nxml-balanced-close-start-tag (block-or-inline)
   (let ((token-end (nxml-token-before))
-       (pos (1+ (point))))
+       (pos (1+ (point)))
+       (token-start xmltok-start))
     (unless (or (eq xmltok-type 'partial-start-tag)
                (and (memq xmltok-type '(start-tag
                                         empty-element
                                         partial-empty-element))
                     (>= token-end pos)))
       (error "Not in a start-tag"))
+    ;; Note that this insertion changes xmltok-start.
     (insert "></"
            (buffer-substring-no-properties (+ xmltok-start 1)
                                            (min xmltok-name-end (point)))
            ">")
     (if (eq block-or-inline 'inline)
        (goto-char pos)
-      (goto-char xmltok-start)
+      (goto-char token-start)
       (back-to-indentation)
-      (if (= (point) xmltok-start)
+      (if (= (point) token-start)
          (let ((indent (current-column)))
-         (goto-char pos)
-         (insert "\n")
-         (indent-line-to indent)
-         (goto-char pos)
-         (insert "\n")
-         (indent-line-to (+ nxml-child-indent indent)))
+           (goto-char pos)
+           (insert "\n")
+           (indent-line-to indent)
+           (goto-char pos)
+           (insert "\n")
+           (indent-line-to (+ nxml-child-indent indent)))
        (goto-char pos)))))
-       
+
 (defun nxml-finish-element ()
   "Finish the current element by inserting an end-tag."
   (interactive "*")
@@ -1364,7 +1371,8 @@ of the inserted start-tag or nil if none was inserted."
   "Indent current line as XML."
   (let ((indent (nxml-compute-indent))
        (from-end (- (point-max) (point))))
-    (when indent
+    (when (and indent
+              (/= indent (current-indentation)))
       (beginning-of-line)
       (let ((bol (point)))
        (skip-chars-forward " \t")
@@ -1474,8 +1482,8 @@ its line.  Otherwise return nil."
 (defun nxml-merge-indent-context-type (context)
   "Merge the indent context type CONTEXT with the token in `xmltok-type'.
 Return the merged indent context type.  An indent context type is
-either nil or one of the symbols start-tag, end-tag, markup, comment,
-mixed."
+either nil or one of the symbols `start-tag', `end-tag', `markup',
+`comment', `mixed'."
   (cond ((memq xmltok-type '(start-tag partial-start-tag))
         (if (memq context '(nil start-tag comment))
             'start-tag
@@ -1567,7 +1575,7 @@ xmltok-* variables to be set up as by `xmltok-forward'."
             (setq atts nil))
            (t (setq atts (cdr atts)))))
     value-boundary))
-            
+
 (defun nxml-compute-indent-in-delimited-token (pos open-delim close-delim)
   "Return the indent for a line that starts inside a token with delimiters.
 OPEN-DELIM and CLOSE-DELIM are strings giving the opening and closing
@@ -1598,7 +1606,7 @@ of the line.  This expects the xmltok-* variables to be set up as by
 Inserts as many characters as can be completed.  However, if not even
 one character can be completed, then a buffer with the possibilities
 is popped up and the symbol is read from the minibuffer with
-completion. If the symbol is complete, then any characters that must
+completion.  If the symbol is complete, then any characters that must
 follow the symbol are also inserted.
 
 The name space used for completion and what is treated as a symbol
@@ -1620,11 +1628,11 @@ This is the equivalent of `forward-sexp' for XML.
 
 An element contains as items strings with no markup, tags, processing
 instructions, comments, CDATA sections, entity references and
-characters references. However, if the variable
+characters references.  However, if the variable
 `nxml-sexp-element-flag' is non-nil, then an element is treated as a
 single markup item.  A start-tag contains an element name followed by
-one or more attributes.  An end-tag contains just an element name.  An
-attribute value literals contains strings with no markup, entity
+one or more attributes.  An end-tag contains just an element name.
+An attribute value literals contains strings with no markup, entity
 references and character references.  A processing instruction
 consists of a target and a content string.  A comment or a CDATA
 section contains a single string.  An entity reference contains a
@@ -2124,7 +2132,7 @@ HAD-DATA says whether there have been non-whitespace data characters yet."
             (goto-char (+ xmltok-start offset))
             (and (re-search-forward "^[ \t]*$" end t)
                  (match-beginning 0)))))
-       ((and (memq xmltok-type '(start-tag 
+       ((and (memq xmltok-type '(start-tag
                                  end-tag
                                  empty-element
                                  comment
@@ -2140,7 +2148,7 @@ HAD-DATA says whether there have been non-whitespace data characters yet."
              (looking-at "[ \t]*$")
              (not (nxml-in-mixed-content-p t)))
         (save-excursion
-          (or (search-forward "\n" nil t) 
+          (or (search-forward "\n" nil t)
               (point-max))))))
 
 (defun nxml-paragraph-start-pos (had-data offset)
@@ -2180,7 +2188,7 @@ HAD-DATA says whether there have been non-whitespace data characters yet."
           (goto-char (- (point) offset))
           (and (re-search-backward "^[ \t]*$" xmltok-start t)
                (match-beginning 0))))
-       ((and (memq xmltok-type '(start-tag 
+       ((and (memq xmltok-type '(start-tag
                                  end-tag
                                  empty-element
                                  comment
@@ -2188,7 +2196,7 @@ HAD-DATA says whether there have been non-whitespace data characters yet."
                                  entity-ref))
              (nxml-token-ends-line-p)
              (nxml-token-begins-line-p))
-        (or (search-forward "\n" nil t) 
+        (or (search-forward "\n" nil t)
             (point-max)))
        ((and (eq xmltok-type 'start-tag)
              (nxml-token-begins-line-p)
@@ -2328,7 +2336,7 @@ ENDP is t in the former case, nil in the latter."
       (fill-region-as-paragraph start end arg))
     (skip-line-prefix fill-prefix)
     fill-prefix))
-    
+
 (defun nxml-newline-and-indent (soft)
   (delete-horizontal-space)
   (if soft (insert-and-inherit ?\n) (newline 1))
@@ -2350,10 +2358,10 @@ point.  The start-tag will be inserted at or before the beginning of
 the word before point; the contents of the current buffer is used to
 decide where.
 
-It works in a similar way to \\[dabbrev-expand]. It searches first
+It works in a similar way to \\[dabbrev-expand].  It searches first
 backwards from point, then forwards from point for an element whose
 content is a string which matches the contents of the buffer before
-point and which includes at least the word before point. It then
+point and which includes at least the word before point.  It then
 copies the start- and end-tags from that element and uses them to
 surround the matching string before point.
 
@@ -2459,11 +2467,11 @@ and attempts to find another possible way to do the markup."
                              (- start-tag-close-pos xmltok-start)))
                (insert "</" name ">")
                (setq nxml-dynamic-markup-prev-pos (point))))))))))
-                                                          
+
 
 ;;; Character names
 
-(defvar nxml-char-name-ignore-case nil)
+(defvar nxml-char-name-ignore-case t)
 
 (defvar nxml-char-name-alist nil
   "Alist of character names.
@@ -2488,10 +2496,10 @@ and NAME is a string naming a character.")
 (defvar nxml-autoload-char-name-set-list nil
   "List of char namesets that can be autoloaded.")
 
-(defun nxml-enable-char-name-set (nameset)    
+(defun nxml-enable-char-name-set (nameset)
   (put nameset 'nxml-char-name-set-enabled t))
 
-(defun nxml-disable-char-name-set (nameset)    
+(defun nxml-disable-char-name-set (nameset)
   (put nameset 'nxml-char-name-set-enabled nil))
 
 (defun nxml-char-name-set-enabled-p (nameset)
@@ -2506,9 +2514,9 @@ and NAME is a string naming a character.")
 (defun nxml-define-char-name-set (nameset alist)
   "Define a set of character names.
 NAMESET is a symbol identifying the set.
-Alist is a list where each member has the form (NAME CODE),
-where NAME is a string naming a character and code
-is an integer giving the Unicode scalar value of the character."
+ALIST is a list where each member has the form (NAME CODE),
+where NAME is a string naming a character and code is an
+integer giving the Unicode scalar value of the character."
   (when (get nameset 'nxml-char-name-set-defined)
     (error "Nameset `%s' already defined" nameset))
   (let ((iter alist))
@@ -2527,7 +2535,7 @@ is an integer giving the Unicode scalar value of the character."
   (put nameset 'nxml-char-name-set-defined t))
 
 (defun nxml-get-char-name (code)
-  (mapcar 'nxml-maybe-load-char-name-set nxml-autoload-char-name-set-list)
+  (mapc 'nxml-maybe-load-char-name-set nxml-autoload-char-name-set-list)
   (let ((names (gethash code nxml-char-name-table))
        name)
     (while (and names (not name))
@@ -2544,7 +2552,7 @@ The name is read from the minibuffer.
 Normally, inserts the character as a numeric character reference.
 With a prefix argument, inserts the character directly."
   (interactive "*P")
-  (mapcar 'nxml-maybe-load-char-name-set nxml-autoload-char-name-set-list)
+  (mapc 'nxml-maybe-load-char-name-set nxml-autoload-char-name-set-list)
   (let ((name
         (let ((completion-ignore-case nxml-char-name-ignore-case))
           (completing-read "Character name: "
@@ -2567,7 +2575,7 @@ With a prefix argument, inserts the character directly."
                      (error "Character %x is not supported by Emacs"
                             code))
                (format "&#x%X;" code))))))
-  
+
 (defun nxml-maybe-load-char-name-set (sym)
   (when (and (get sym 'nxml-char-name-set-enabled)
             (not (get sym 'nxml-char-name-set-defined))
@@ -2575,20 +2583,14 @@ With a prefix argument, inserts the character directly."
     (load (get sym 'nxml-char-name-set-file))))
 
 (defun nxml-toggle-char-ref-extra-display (arg)
-  "*Toggle the display of extra information for character references."
+  "Toggle the display of extra information for character references."
   (interactive "P")
   (let ((new (if (null arg)
                 (not nxml-char-ref-extra-display)
               (> (prefix-numeric-value arg) 0))))
     (when (not (eq new nxml-char-ref-extra-display))
       (setq nxml-char-ref-extra-display new)
-      (save-excursion
-       (save-restriction
-         (widen)
-         (if nxml-char-ref-extra-display
-             (nxml-with-unmodifying-text-property-changes
-               (nxml-clear-fontified (point-min) (point-max)))
-           (nxml-clear-char-ref-extra-display (point-min) (point-max))))))))
+      (font-lock-fontify-buffer))))
 
 (put 'nxml-char-ref 'evaporate t)
 
@@ -2596,7 +2598,7 @@ With a prefix argument, inserts the character directly."
   (when nxml-char-ref-extra-display
     (let ((name (nxml-get-char-name n))
          (glyph-string (and nxml-char-ref-display-glyph-flag
-                            (nxml-glyph-display-string n 'nxml-glyph-face)))
+                            (nxml-glyph-display-string n 'nxml-glyph)))
          ov)
     (when (or name glyph-string)
       (setq ov (make-overlay start end nil t))
@@ -2606,7 +2608,7 @@ With a prefix argument, inserts the character directly."
       (when glyph-string
        (overlay-put ov
                     'after-string
-                    (propertize glyph-string 'face 'nxml-glyph-face)))))))
+                    (propertize glyph-string 'face 'nxml-glyph)))))))
 
 (defun nxml-clear-char-ref-extra-display (start end)
   (let ((ov (overlays-in start end)))
@@ -2615,20 +2617,11 @@ With a prefix argument, inserts the character directly."
        (delete-overlay (car ov)))
       (setq ov (cdr ov)))))
 
-;;; Versioning
-
-(defun nxml-version ()
-  "Show the version of nXML mode that is being used."
-  (interactive)
-  (if nxml-version
-      (message "nXML mode version %s" nxml-version)
-    (message "nXML mode version unknown")))
-
 
 (defun nxml-start-delimiter-length (type)
   (or (get type 'nxml-start-delimiter-length)
       0))
-                       
+
 (put 'cdata-section 'nxml-start-delimiter-length 9)
 (put 'comment 'nxml-start-delimiter-length 4)
 (put 'processing-instruction 'nxml-start-delimiter-length 2)
@@ -2641,7 +2634,7 @@ With a prefix argument, inserts the character directly."
 (defun nxml-end-delimiter-length (type)
   (or (get type 'nxml-end-delimiter-length)
       0))
-                       
+
 (put 'cdata-section 'nxml-end-delimiter-length 3)
 (put 'comment 'nxml-end-delimiter-length 3)
 (put 'processing-instruction 'nxml-end-delimiter-length 2)
@@ -2660,6 +2653,9 @@ With a prefix argument, inserts the character directly."
 (put 'entity-ref 'nxml-friendly-name "entity reference")
 (put 'char-ref 'nxml-friendly-name "character reference")
 
+;;;###autoload
+(defalias 'xml-mode 'nxml-mode)
+
 (provide 'nxml-mode)
 
 ;; arch-tag: 8603bc5f-1ef9-4021-b223-322fb2ca708e