declare smobs in alloc.c
[bpt/emacs.git] / lisp / nxml / nxml-mode.el
index a22288e..4859bbc 100644 (file)
@@ -1,9 +1,9 @@
-;;; nxml-mode.el --- a new XML mode
+;;; nxml-mode.el --- a new XML mode  -*- lexical-binding:t -*-
 
-;; Copyright (C) 2003-2004, 2007-201 Free Software Foundation, Inc.
+;; Copyright (C) 2003-2004, 2007-2014 Free Software Foundation, Inc.
 
 ;; Author: James Clark
-;; Keywords: XML
+;; Keywords: wp, hypermedia, languages, XML
 
 ;; This file is part of GNU Emacs.
 
@@ -29,7 +29,7 @@
 (when (featurep 'mucs)
   (error "nxml-mode is not compatible with Mule-UCS"))
 
-(eval-when-compile (require 'cl))      ; for assert
+(eval-when-compile (require 'cl-lib))
 
 (require 'xmltok)
 (require 'nxml-enc)
@@ -46,6 +46,7 @@
 
 (defgroup nxml nil
   "New XML editing mode."
+  :link '(custom-manual "(nxml-mode) Top")
   :group 'languages)
 
 (defgroup nxml-faces nil
@@ -54,9 +55,9 @@
 
 (defcustom nxml-char-ref-display-glyph-flag t
   "Non-nil means display glyph following character reference.
-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."
+The glyph is displayed in face `nxml-glyph'.  The abnormal hook
+`nxml-glyph-set-functions' can be used to change the characters
+for which glyphs are displayed."
   :group 'nxml
   :type 'boolean)
 
@@ -86,18 +87,9 @@ as the first attribute on the previous line."
   :group 'nxml
   :type 'integer)
 
-(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 for `nxml-complete' when both are bound.  So it's better
-to bind M-TAB only when it will work."
+(defcustom nxml-bind-meta-tab-to-complete-flag t
+  "Non-nil means to use nXML completion in \\[completion-at-point]."
   :group 'nxml
-  :set (lambda (sym flag)
-        (set-default sym flag)
-        (when (and (boundp 'nxml-mode-map) nxml-mode-map)
-          (define-key nxml-mode-map "\M-\t" (and flag 'nxml-complete))))
   :type 'boolean)
 
 (defcustom nxml-prefer-utf-16-to-utf-8-flag nil
@@ -168,12 +160,12 @@ This is not used directly, but only via inheritance by other faces."
 
 (defface nxml-comment-delimiter
   '((t (:inherit font-lock-comment-delimiter-face)))
-  "Face used for the delimiters of comments, i.e <!-- and -->."
+  "Face used for the delimiters of comments, i.e., <!-- and -->."
   :group 'nxml-faces)
 
 (defface nxml-processing-instruction-delimiter
   '((t (:inherit nxml-delimiter)))
-  "Face used for the delimiters of processing instructions, i.e <? and ?>."
+  "Face used for the delimiters of processing instructions, i.e., <? and ?>."
   :group 'nxml-faces)
 
 (defface nxml-processing-instruction-target
@@ -188,7 +180,7 @@ This is not used directly, but only via inheritance by other faces."
 
 (defface nxml-cdata-section-delimiter
   '((t (:inherit nxml-delimiter)))
-  "Face used for the delimiters of CDATA sections, i.e <![, [, and ]]>."
+  "Face used for the delimiters of CDATA sections, i.e., <![, [, and ]]>."
   :group 'nxml-faces)
 
 (defface nxml-cdata-section-CDATA
@@ -209,7 +201,7 @@ This includes ths `x' in hex references."
 
 (defface nxml-char-ref-delimiter
   '((t (:inherit nxml-ref)))
-  "Face used for the delimiters of character references, i.e &# and ;."
+  "Face used for the delimiters of character references, i.e., &# and ;."
   :group 'nxml-faces)
 
 (defface nxml-entity-ref-name
@@ -219,7 +211,7 @@ This includes ths `x' in hex references."
 
 (defface nxml-entity-ref-delimiter
   '((t (:inherit nxml-ref)))
-  "Face used for the delimiters of entity references, i.e & and ;."
+  "Face used for the delimiters of entity references, i.e., & and ;."
   :group 'nxml-faces)
 
 (defface nxml-tag-delimiter
@@ -361,11 +353,6 @@ Use `nxml-parent-document-set' to set it.")
 See the function `xmltok-forward-prolog' for more information.")
 (make-variable-buffer-local 'nxml-prolog-regions)
 
-(defvar nxml-last-fontify-end nil
-  "Position where fontification last ended.
-It is nil if the buffer changed since the last fontification.")
-(make-variable-buffer-local 'nxml-last-fontify-end)
-
 (defvar nxml-degraded nil
   "Non-nil if currently operating in degraded mode.
 Degraded mode is enabled when an internal error is encountered in the
@@ -418,9 +405,7 @@ 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)
-    (when nxml-bind-meta-tab-to-complete-flag
-      (define-key map "\M-\t" 'nxml-complete))
+    (define-key map "\M-\t" 'completion-at-point)
     map)
   "Keymap for nxml-mode.")
 
@@ -479,7 +464,7 @@ 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 `</'
 automatically inserts the rest of the end-tag.
 
-\\[nxml-complete] performs completion on the symbol preceding point.
+\\[completion-at-point] performs completion on the symbol preceding point.
 
 \\[nxml-dynamic-markup-word] uses the contents of the current buffer
 to choose a tag to put around the word preceding point.
@@ -549,20 +534,21 @@ Many aspects this mode can be customized using
   (save-excursion
     (save-restriction
       (widen)
-      (nxml-clear-dependent-regions (point-min) (point-max))
       (setq nxml-scan-end (copy-marker (point-min) nil))
-      (nxml-with-unmodifying-text-property-changes
+      (with-silent-modifications
         (nxml-clear-inside (point-min) (point-max))
        (nxml-with-invisible-motion
          (nxml-scan-prolog)))))
-  (add-hook 'after-change-functions 'nxml-after-change nil t)
+  (add-hook 'completion-at-point-functions
+            #'nxml-completion-at-point-function nil t)
+  (setq-local syntax-propertize-function #'nxml-after-change)
   (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)
+  ;;(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)))
@@ -576,8 +562,6 @@ Many aspects this mode can be customized using
           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)))
@@ -592,12 +576,9 @@ Many aspects this mode can be customized using
   ;; Clean up fontification.
   (save-excursion
     (widen)
-    (let ((inhibit-read-only t)
-         (buffer-undo-list t)
-         (modified (buffer-modified-p)))
+    (with-silent-modifications
       (nxml-with-invisible-motion
-       (remove-text-properties (point-min) (point-max) '(face)))
-      (set-buffer-modified-p modified)))
+       (remove-text-properties (point-min) (point-max) '(face)))))
   (remove-hook 'change-major-mode-hook 'nxml-cleanup t))
 
 (defun nxml-degrade (context err)
@@ -610,11 +591,12 @@ Many aspects this mode can be customized using
   (save-excursion
     (save-restriction
       (widen)
-      (nxml-with-unmodifying-text-property-changes
+      (with-silent-modifications
        (nxml-clear-inside (point-min) (point-max))))))
 
 ;;; Change management
 
+(defvar font-lock-beg) (defvar font-lock-end)
 (defun nxml-debug-region (start end)
   (interactive "r")
   (let ((font-lock-beg start)
@@ -623,22 +605,16 @@ Many aspects this mode can be customized using
     (goto-char font-lock-beg)
     (set-mark font-lock-end)))
 
-(defun nxml-after-change (start end pre-change-length)
-  ; 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)
+(defun nxml-after-change (start end)
+  ;; Called via syntax-propertize-function.
+  (unless 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)
+      (save-restriction
+        (widen)
+        (nxml-with-invisible-motion
+         (nxml-after-change1 start end))))))
+
+(defun nxml-after-change1 (start end)
   "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
@@ -646,27 +622,14 @@ 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 (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 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)
-      (setq start (point-min))))
+  ;; 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 (document element), since changing
+            ;; these can change where the prolog ends.
+            (+ nxml-prolog-end 2))
+    (nxml-scan-prolog)
+    (setq start (point-min)))
 
   (when (> end nxml-prolog-end)
     (goto-char start)
@@ -675,8 +638,7 @@ disabled."
     (setq end (max (nxml-scan-after-change start end)
                    end)))
 
-  (nxml-debug-change "nxml-after-change1" start end)
-  (cons start end))
+  (nxml-debug-change "nxml-after-change1" start end))
 
 ;;; Encodings
 
@@ -867,7 +829,6 @@ The XML declaration will declare an encoding depending on the buffer's
   (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."
@@ -909,49 +870,25 @@ Called with `font-lock-beg' and `font-lock-end' dynamically bound."
       (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."
-
+  (syntax-propertize bound)
   (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
+      ;; Prolog needs to be fontified in one go, and
       ;; nxml-extend-region makes sure we start at BOB.
-      (assert (bobp))
+      (cl-assert (bobp))
       (nxml-fontify-prolog)
       (goto-char nxml-prolog-end))
 
-    (let (xmltok-dependent-regions
-          xmltok-errors)
+    (let (xmltok-errors)
       (while (and (nxml-tokenize-forward)
-                  (<= (point) bound)) ; intervals are open-ended
+                  (<= (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.
@@ -1245,7 +1182,7 @@ on the line, reindent the line."
     (unless arg
       (if nxml-slash-auto-complete-flag
          (if end-tag-p
-             (condition-case err
+             (condition-case nil
                  (let ((start-tag-end
                         (nxml-scan-element-backward (1- slash-pos) t)))
                    (when start-tag-end
@@ -1443,7 +1380,7 @@ its line.  Otherwise return nil."
                 (nxml-token-after)
                 (= xmltok-start bol))
               (eq xmltok-type 'data))
-          (condition-case err
+          (condition-case nil
               (nxml-scan-element-backward
                (point)
                nil
@@ -1568,8 +1505,7 @@ This expects the xmltok-* variables to be set up as by `xmltok-forward'."
        (off 0))
     (if value-boundary
        ;; inside an attribute value
-       (let ((value-start (car value-boundary))
-             (value-end (cdr value-boundary)))
+       (let ((value-start (car value-boundary)))
          (goto-char pos)
          (forward-line -1)
          (if (< (point) value-start)
@@ -1654,6 +1590,11 @@ depend on `nxml-completion-hook'."
     (ding)
     (message "Cannot complete in this context")))
 
+(defun nxml-completion-at-point-function ()
+  "Call `nxml-complete' to perform completion at point."
+  (when nxml-bind-meta-tab-to-complete-flag
+    #'nxml-complete))
+
 ;;; Movement
 
 (defun nxml-forward-balanced-item (&optional arg)
@@ -1757,7 +1698,7 @@ single name.  A character reference contains a character number."
         xmltok-name-end)
        (t end)))
 
-(defun nxml-scan-backward-within (end)
+(defun nxml-scan-backward-within (_end)
   (setq xmltok-start
        (+ xmltok-start
           (nxml-start-delimiter-length xmltok-type)))
@@ -2267,7 +2208,7 @@ ENDP is t in the former case, nil in the latter."
                 'nxml-in-mixed-content-hook))
           nil)
          ;; See if the matching tag does not start or end a line.
-         ((condition-case err
+         ((condition-case nil
               (progn
                 (setq matching-tag-pos
                       (xmltok-save
@@ -2405,7 +2346,7 @@ Repeating \\[nxml-dynamic-markup-word] immediately after successful
 \\[nxml-dynamic-markup-word] removes the previously inserted markup
 and attempts to find another possible way to do the markup."
   (interactive "*")
-  (let (search-start-pos done)
+  (let (search-start-pos)
     (if (and (integerp nxml-dynamic-markup-prev-pos)
             (= nxml-dynamic-markup-prev-pos (point))
             (eq last-command this-command)
@@ -2626,7 +2567,7 @@ With a prefix argument, inserts the character directly."
               (> (prefix-numeric-value arg) 0))))
     (when (not (eq new nxml-char-ref-extra-display))
       (setq nxml-char-ref-extra-display new)
-      (font-lock-fontify-buffer))))
+      (font-lock-flush))))
 
 (put 'nxml-char-ref 'evaporate t)
 
@@ -2689,8 +2630,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)
+;; Only do this in loaddefs, so that if someone defines a different
+;; alias in .emacs, loading this file afterwards does not clobber it.
+;;;###autoload(defalias 'xml-mode 'nxml-mode)
 
 (provide 'nxml-mode)