Mercurial > emacs
annotate lisp/nxml/rng-valid.el @ 112353:71904feb29f6
Improve performance on non-GCC hosts with __aligned__.
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Mon, 17 Jan 2011 20:55:12 -0800 |
parents | 61f7601898b1 |
children |
rev | line source |
---|---|
86361 | 1 ;;; rng-valid.el --- real-time validation of XML using RELAX NG |
2 | |
112284
61f7601898b1
Refill some copyright headers.
Glenn Morris <rgm@gnu.org>
parents:
112228
diff
changeset
|
3 ;; Copyright (C) 2003, 2007, 2008, 2009, 2010, 2011 |
61f7601898b1
Refill some copyright headers.
Glenn Morris <rgm@gnu.org>
parents:
112228
diff
changeset
|
4 ;; Free Software Foundation, Inc. |
86361 | 5 |
6 ;; Author: James Clark | |
7 ;; Keywords: XML, RelaxNG | |
8 | |
86555 | 9 ;; This file is part of GNU Emacs. |
10 | |
94666
d495d4d5452f
Switch to recommended form of GPLv3 permissions notice.
Glenn Morris <rgm@gnu.org>
parents:
87665
diff
changeset
|
11 ;; GNU Emacs is free software: you can redistribute it and/or modify |
86555 | 12 ;; it under the terms of the GNU General Public License as published by |
94666
d495d4d5452f
Switch to recommended form of GPLv3 permissions notice.
Glenn Morris <rgm@gnu.org>
parents:
87665
diff
changeset
|
13 ;; the Free Software Foundation, either version 3 of the License, or |
d495d4d5452f
Switch to recommended form of GPLv3 permissions notice.
Glenn Morris <rgm@gnu.org>
parents:
87665
diff
changeset
|
14 ;; (at your option) any later version. |
86361 | 15 |
86555 | 16 ;; GNU Emacs is distributed in the hope that it will be useful, |
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 ;; GNU General Public License for more details. | |
86361 | 20 |
86555 | 21 ;; You should have received a copy of the GNU General Public License |
94666
d495d4d5452f
Switch to recommended form of GPLv3 permissions notice.
Glenn Morris <rgm@gnu.org>
parents:
87665
diff
changeset
|
22 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
86361 | 23 |
24 ;;; Commentary: | |
25 | |
26 ;; For usage information, see the documentation for rng-validate-mode. | |
27 ;; | |
28 ;; This file provides a minor mode that continually validates a buffer | |
29 ;; against a RELAX NG schema. The validation state is used to support | |
30 ;; schema-sensitive editing as well as validation. Validation is | |
31 ;; performed while Emacs is idle. XML parsing is done using | |
32 ;; xmltok.el. This file is responsible for checking that end-tags | |
33 ;; match their start-tags. Namespace processing is handled by | |
34 ;; nxml-ns.el. The RELAX NG Compact Syntax schema is parsed into | |
35 ;; internal form by rng-cmpct.el. This internal form is described by | |
36 ;; rng-pttrn.el. Validation of the document by matching against this | |
37 ;; internal form is done by rng-match.el. Handling of W3C XML Schema | |
38 ;; datatypes is delegated by rng-match.el to rng-xsd.el. The minor | |
39 ;; mode is intended to be used in conjunction with the nxml major | |
40 ;; mode, but does not have to be. | |
41 ;; | |
42 ;; The major responsibility of this file is to allow validation to | |
43 ;; happen incrementally. If a buffer has been validated and is then | |
44 ;; changed, we can often revalidate it without having to completely | |
45 ;; parse and validate it from start to end. As we parse and validate | |
46 ;; the buffer, we periodically cache the state. The state has three | |
47 ;; components: the stack of open elements, the namespace processing | |
48 ;; state and the RELAX NG validation state. The state is cached as the | |
49 ;; value of the rng-state text property on the closing greater-than of | |
50 ;; tags (but at intervals, not on every tag). We keep track of the | |
51 ;; position up to which cached state is known to be correct by adding | |
52 ;; a function to the buffer's after-change-functions. This is stored | |
53 ;; in the rng-validate-up-to-date-end variable. The first way in | |
54 ;; which we make validation incremental is obvious: we start | |
55 ;; validation from the first cached state before | |
56 ;; rng-validate-up-to-date-end. | |
57 ;; | |
58 ;; To make this work efficiently, we have to be able to copy the | |
59 ;; current parsing and validation state efficiently. We do this by | |
60 ;; minimizing destructive changes to the objects storing the state. | |
61 ;; When state is changed, we use the old state to create new objects | |
62 ;; representing the new state rather than destructively modifying the | |
63 ;; objects representing the old state. Copying the state is just a | |
64 ;; matter of making a list of three objects, one for each component of | |
65 ;; the state; the three objects themselves can be shared and do not | |
66 ;; need to be copied. | |
67 ;; | |
68 ;; There's one other idea that is used to make validation incremental. | |
69 ;; Suppose we have a buffer that's 4000 bytes long and suppose we | |
70 ;; validated it, caching state at positions 1000, 2000 and 3000. Now | |
71 ;; suppose we make a change at position 1500 inserting 100 characters. | |
72 ;; rng-validate-up-to-date-end will be changed to 1500. When Emacs | |
73 ;; becomes idle and we revalidate, validation will restart using the | |
74 ;; cached state at position 1000. However, we take advantage of the | |
75 ;; cached state beyond rng-validate-up-to-date-end as follows. When | |
76 ;; our validation reaches position 2100 (the current position of the | |
77 ;; character that was at 2000), we compare our current state with the | |
78 ;; cached state. If they are the same, then we can stop parsing | |
79 ;; immediately and set rng-validate-up-to-date-end to the end of the | |
80 ;; buffer: we already know that the state cached at position 3100 is | |
81 ;; correct. If they are not the same, then we have to continue | |
82 ;; parsing. After the change, but before revalidation, we call the | |
83 ;; region from 1600 to the end of the buffer "conditionally | |
84 ;; up-to-date". | |
85 ;; | |
86 ;; As well as the cached parsing and validation state, we also keep | |
87 ;; track of the errors in the file. Errors are stored as overlays | |
88 ;; with a category of rng-error. The number of such overlays in the | |
89 ;; buffer must always be equal to rng-error-count. | |
90 | |
91 ;;; Code: | |
92 | |
93 (require 'xmltok) | |
94 (require 'nxml-enc) | |
95 (require 'nxml-util) | |
96 (require 'nxml-ns) | |
97 (require 'rng-match) | |
98 (require 'rng-util) | |
99 (require 'rng-loc) | |
100 | |
101 ;;; Customizable variables | |
102 | |
103 (defgroup relax-ng nil | |
104 "Validation of XML using RELAX NG." | |
105 :group 'wp | |
106 :group 'nxml | |
107 :group 'languages) | |
108 | |
87346
c5910db8e06e
(rng-error): Rename from rng-error-face.
Jason Rumney <jasonr@gnu.org>
parents:
86555
diff
changeset
|
109 (defface rng-error '((t (:inherit font-lock-warning-face))) |
86361 | 110 "Face for highlighting XML errors." |
111 :group 'relax-ng) | |
112 | |
113 (defcustom rng-state-cache-distance 2000 | |
111801
c06fec785962
Remove leading `*' from nxml defcustom docs.
Glenn Morris <rgm@gnu.org>
parents:
111782
diff
changeset
|
114 "Distance in characters between each parsing and validation state cache." |
86361 | 115 :type 'integer |
116 :group 'relax-ng) | |
117 | |
118 (defcustom rng-validate-chunk-size 8000 | |
111801
c06fec785962
Remove leading `*' from nxml defcustom docs.
Glenn Morris <rgm@gnu.org>
parents:
111782
diff
changeset
|
119 "Number of characters in a RELAX NG validation chunk. |
86361 | 120 A validation chunk will be the smallest chunk that is at least this |
121 size and ends with a tag. After validating a chunk, validation will | |
122 continue only if Emacs is still idle." | |
123 :type 'integer | |
124 :group 'relax-ng) | |
125 | |
126 (defcustom rng-validate-delay 1.5 | |
111801
c06fec785962
Remove leading `*' from nxml defcustom docs.
Glenn Morris <rgm@gnu.org>
parents:
111782
diff
changeset
|
127 "Time in seconds that Emacs must be idle before starting a full validation. |
86361 | 128 A full validation continues until either validation is up to date |
129 or Emacs is no longer idle." | |
130 :type 'number | |
131 :group 'relax-ng) | |
132 | |
133 (defcustom rng-validate-quick-delay 0.3 | |
111801
c06fec785962
Remove leading `*' from nxml defcustom docs.
Glenn Morris <rgm@gnu.org>
parents:
111782
diff
changeset
|
134 "Time in seconds that Emacs must be idle before starting a quick validation. |
86361 | 135 A quick validation validates at most one chunk." |
136 :type 'number | |
137 :group 'relax-ng) | |
138 | |
139 ;; Global variables | |
140 | |
141 (defvar rng-validate-timer nil) | |
142 (make-variable-buffer-local 'rng-validate-timer) | |
143 ;; ensure that we can cancel the timer even after a kill-all-local-variables | |
144 (put 'rng-validate-timer 'permanent-local t) | |
145 | |
146 (defvar rng-validate-quick-timer nil) | |
147 (make-variable-buffer-local 'rng-validate-quick-timer) | |
148 ;; ensure that we can cancel the timer even after a kill-all-local-variables | |
149 (put 'rng-validate-quick-timer 'permanent-local t) | |
150 | |
151 (defvar rng-error-count nil | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
152 "Number of errors in the current buffer. |
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
153 Always equal to number of overlays with category `rng-error'.") |
86361 | 154 (make-variable-buffer-local 'rng-error-count) |
155 | |
156 (defvar rng-message-overlay nil | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
157 "Overlay in this buffer whose `help-echo' property was last printed. |
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
158 It is nil if none.") |
86361 | 159 (make-variable-buffer-local 'rng-message-overlay) |
160 | |
161 (defvar rng-message-overlay-inhibit-point nil | |
162 "Position at which message from overlay should be inhibited. | |
163 If point is equal to this and the error overlay around | |
164 point is `rng-message-overlay', then the `help-echo' property | |
165 of the error overlay should not be printed with `message'.") | |
166 (make-variable-buffer-local 'rng-message-overlay-inhibit-point) | |
167 | |
168 (defvar rng-message-overlay-current nil | |
169 "Non-nil if `rng-message-overlay' is still the current message.") | |
170 (make-variable-buffer-local 'rng-message-overlay-current) | |
171 | |
172 (defvar rng-open-elements nil | |
173 "Stack of names of open elements represented as a list. | |
174 Each member of the list is either t or a (PREFIX . LOCAL-NAME) pair. | |
175 \(PREFIX . LOCAL-NAME) is pushed for a start-tag; t is pushed | |
176 for a mismatched end-tag.") | |
177 | |
178 (defvar rng-pending-contents nil | |
179 "Text content of current element that has yet to be processed. | |
180 Value is a list of segments (VALUE START END) positions in reverse | |
181 order. VALUE is a string or nil. If VALUE is nil, then the value is | |
182 the string between START and END. A segment can also be nil | |
183 indicating an unresolvable entity or character reference.") | |
184 | |
185 (defvar rng-collecting-text nil) | |
186 | |
187 (defvar rng-validate-up-to-date-end nil | |
188 "Last position where validation is known to be up to date.") | |
189 (make-variable-buffer-local 'rng-validate-up-to-date-end) | |
190 | |
191 (defvar rng-conditional-up-to-date-start nil | |
192 "Marker for the start of the conditionally up-to-date region. | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
193 It is nil if there is no conditionally up-to-date region. The |
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
194 conditionally up-to-date region must be such that for any cached |
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
195 state S with position P in the conditionally up-to-date region, |
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
196 if at some point it is determined that S becomes correct for P, |
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
197 then all states with position >= P in the conditionally up to |
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
198 date region must also then be correct and all errors between P |
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
199 and the end of the region must then be correctly marked.") |
86361 | 200 (make-variable-buffer-local 'rng-conditional-up-to-date-start) |
201 | |
202 (defvar rng-conditional-up-to-date-end nil | |
203 "Marker for the end of the conditionally up-to-date region. | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
204 It is nil if there is no conditionally up-to-date region. |
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
205 See the variable `rng-conditional-up-to-date-start'.") |
86361 | 206 (make-variable-buffer-local 'rng-conditional-up-to-date-end) |
207 | |
208 (defvar rng-parsing-for-state nil | |
209 "Non-nil means we are currently parsing just to compute the state. | |
210 Should be dynamically bound.") | |
211 | |
212 (defvar rng-validate-mode nil) | |
213 (make-variable-buffer-local 'rng-validate-mode) | |
214 | |
215 (defvar rng-dtd nil) | |
216 (make-variable-buffer-local 'rng-dtd) | |
217 | |
218 ;;;###autoload | |
219 (defun rng-validate-mode (&optional arg no-change-schema) | |
220 "Minor mode performing continual validation against a RELAX NG schema. | |
221 | |
222 Checks whether the buffer is a well-formed XML 1.0 document, | |
223 conforming to the XML Namespaces Recommendation and valid against a | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
224 RELAX NG schema. The mode-line indicates whether it is or not. Any |
86361 | 225 parts of the buffer that cause it not to be are considered errors and |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
226 are highlighted with face `rng-error'. A description of each error is |
86361 | 227 available as a tooltip. \\[rng-next-error] goes to the next error |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
228 after point. Clicking mouse-1 on the word `Invalid' in the mode-line |
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
229 goes to the first error in the buffer. If the buffer changes, then it |
86361 | 230 will be automatically rechecked when Emacs becomes idle; the |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
231 rechecking will be paused whenever there is input pending. |
86361 | 232 |
233 By default, uses a vacuous schema that allows any well-formed XML | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
234 document. A schema can be specified explictly using |
86361 | 235 \\[rng-set-schema-file-and-validate], or implicitly based on the buffer's |
236 file name or on the root element name. In each case the schema must | |
237 be a RELAX NG schema using the compact schema \(such schemas | |
238 conventionally have a suffix of `.rnc'). The variable | |
239 `rng-schema-locating-files' specifies files containing rules | |
240 to use for finding the schema." | |
241 (interactive "P") | |
242 (setq rng-validate-mode | |
243 (if (null arg) | |
244 (not rng-validate-mode) | |
245 (> (prefix-numeric-value arg) 0))) | |
246 (save-restriction | |
247 (widen) | |
248 (nxml-with-unmodifying-text-property-changes | |
249 (rng-clear-cached-state (point-min) (point-max))) | |
250 ;; 1+ to clear empty overlays at (point-max) | |
106307
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
251 (rng-clear-overlays (point-min) (1+ (point-max))) |
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
252 (setq rng-validate-up-to-date-end (point-min))) |
86361 | 253 (rng-clear-conditional-region) |
254 (setq rng-error-count 0) | |
255 ;; do this here to avoid infinite loop if we set the schema | |
256 (remove-hook 'rng-schema-change-hook 'rng-validate-clear t) | |
257 (cond (rng-validate-mode | |
258 (unwind-protect | |
259 (save-excursion | |
260 ;; An error can change the current buffer | |
261 (when (or (not rng-current-schema) | |
262 (and (eq rng-current-schema rng-any-element) | |
263 (not no-change-schema))) | |
264 (rng-auto-set-schema t))) | |
265 (unless rng-current-schema (rng-set-schema-file-1 nil)) | |
266 (add-hook 'rng-schema-change-hook 'rng-validate-clear nil t) | |
267 (add-hook 'after-change-functions 'rng-after-change-function nil t) | |
268 (add-hook 'kill-buffer-hook 'rng-kill-timers nil t) | |
269 (add-hook 'echo-area-clear-hook 'rng-echo-area-clear-function nil t) | |
270 (add-hook 'post-command-hook 'rng-maybe-echo-error-at-point nil t) | |
271 (rng-match-init-buffer) | |
272 (rng-activate-timers) | |
273 ;; Start validating right away if the buffer is visible. | |
274 ;; If it's not visible, don't do this, because the user | |
275 ;; won't get any progress indication. When the user finds | |
276 ;; a new file, then the buffer won't be visible | |
277 ;; when this is invoked. | |
278 (when (get-buffer-window (current-buffer) 'visible) | |
279 (rng-validate-while-idle (current-buffer))))) | |
280 (t | |
281 (rng-cancel-timers) | |
282 (force-mode-line-update) | |
283 (remove-hook 'kill-buffer-hook 'rng-cancel-timers t) | |
284 (remove-hook 'post-command-hook 'rng-maybe-echo-error-at-point t) | |
285 (remove-hook 'echo-area-clear-hook 'rng-echo-area-clear-function t) | |
286 (remove-hook 'after-change-functions 'rng-after-change-function t)))) | |
287 | |
288 (defun rng-set-schema-file-and-validate (filename) | |
289 "Sets the schema and turns on `rng-validate-mode' if not already on. | |
290 The schema is set like `rng-set-schema'." | |
291 (interactive "fSchema file: ") | |
292 (rng-set-schema-file filename) | |
293 (or rng-validate-mode (rng-validate-mode))) | |
294 | |
295 (defun rng-set-document-type-and-validate (type-id) | |
296 (interactive (list (rng-read-type-id))) | |
297 (and (rng-set-document-type type-id) | |
298 (or rng-validate-mode (rng-validate-mode)))) | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
299 |
86361 | 300 (defun rng-auto-set-schema-and-validate () |
301 "Set the schema for this buffer automatically and turn on `rng-validate-mode'. | |
302 The schema is set like `rng-auto-set-schema'." | |
303 (interactive) | |
304 (rng-auto-set-schema) | |
305 (or rng-validate-mode (rng-validate-mode))) | |
306 | |
307 (defun rng-after-change-function (start end pre-change-len) | |
308 (setq rng-message-overlay-inhibit-point nil) | |
309 (nxml-with-unmodifying-text-property-changes | |
310 (rng-clear-cached-state start end)) | |
311 ;; rng-validate-up-to-date-end holds the position before the change | |
312 ;; Adjust it to reflect the change. | |
313 (if (< start rng-validate-up-to-date-end) | |
314 (setq rng-validate-up-to-date-end | |
315 (if (<= (+ start pre-change-len) rng-validate-up-to-date-end) | |
316 (+ rng-validate-up-to-date-end | |
317 (- end start pre-change-len)) | |
318 start))) | |
319 ;; Adjust the conditional zone | |
320 (cond (rng-conditional-up-to-date-start | |
321 (when (< rng-conditional-up-to-date-start end) | |
322 (if (< end rng-conditional-up-to-date-end) | |
323 (set-marker rng-conditional-up-to-date-start end) | |
324 (rng-clear-conditional-region)))) | |
325 ((< end rng-validate-up-to-date-end) | |
326 (setq rng-conditional-up-to-date-end | |
327 (copy-marker rng-validate-up-to-date-end nil)) | |
328 (setq rng-conditional-up-to-date-start | |
329 (copy-marker end t)))) | |
330 ;; Adjust rng-validate-up-to-date-end | |
331 (if (< start rng-validate-up-to-date-end) | |
332 (setq rng-validate-up-to-date-end start)) | |
333 ;; Must make rng-validate-up-to-date-end < point-max | |
334 ;; (unless the buffer is empty). | |
106307
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
335 ;; otherwise rng-validate-prepare will say there's nothing to do. |
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
336 (when (>= rng-validate-up-to-date-end (point-max)) |
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
337 (setq rng-validate-up-to-date-end |
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
338 (if (< (point-min) (point-max)) |
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
339 (1- (point-max)) |
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
340 ;; Only widen if really necessary. |
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
341 (save-restriction (widen) (max (point-min) (1- (point-max))))))) |
86361 | 342 ;; Arrange to revalidate |
343 (rng-activate-timers) | |
344 ;; Need to do this after activating the timer | |
345 (force-mode-line-update)) | |
346 | |
347 (defun rng-compute-mode-line-string () | |
348 (cond (rng-validate-timer | |
349 (concat " Validated:" | |
350 (number-to-string | |
351 ;; Use floor rather than round because we want | |
352 ;; to show 99% rather than 100% for changes near | |
353 ;; the end. | |
354 (floor (if (eq (buffer-size) 0) | |
355 0.0 | |
106307
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
356 (/ (* (- rng-validate-up-to-date-end (point-min)) |
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
357 100.0) |
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
358 (- (point-max) (point-min)))))) |
86361 | 359 "%%")) |
360 ((> rng-error-count 0) | |
361 (concat " " | |
362 (propertize "Invalid" | |
363 'help-echo "mouse-1: go to first error" | |
364 'local-map (make-mode-line-mouse-map | |
365 'mouse-1 | |
366 'rng-mouse-first-error)))) | |
367 (t " Valid"))) | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
368 |
86361 | 369 (defun rng-cancel-timers () |
370 (let ((inhibit-quit t)) | |
371 (when rng-validate-timer | |
372 (cancel-timer rng-validate-timer) | |
373 (setq rng-validate-timer nil)) | |
374 (when rng-validate-quick-timer | |
375 (cancel-timer rng-validate-quick-timer) | |
376 (setq rng-validate-quick-timer nil)))) | |
377 | |
378 (defun rng-kill-timers () | |
379 ;; rng-validate-timer and rng-validate-quick-timer have the | |
380 ;; permanent-local property, so that the timers can be | |
381 ;; cancelled even after changing mode. | |
382 ;; This function takes care of cancelling the timers and | |
383 ;; then killing the local variables. | |
384 (when (local-variable-p 'rng-validate-timer) | |
385 (when rng-validate-timer | |
386 (cancel-timer rng-validate-timer)) | |
387 (kill-local-variable 'rng-validate-timer)) | |
388 (when (local-variable-p 'rng-validate-quick-timer) | |
389 (when rng-validate-quick-timer | |
390 (cancel-timer rng-validate-quick-timer)) | |
391 (kill-local-variable 'rng-validate-quick-timer))) | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
392 |
86361 | 393 (defun rng-activate-timers () |
394 (unless rng-validate-timer | |
395 (let ((inhibit-quit t)) | |
396 (setq rng-validate-timer | |
397 (run-with-idle-timer rng-validate-delay | |
398 t | |
399 'rng-validate-while-idle | |
400 (current-buffer))) | |
401 (setq rng-validate-quick-timer | |
402 (run-with-idle-timer rng-validate-quick-delay | |
403 t | |
404 'rng-validate-quick-while-idle | |
405 (current-buffer)))))) | |
406 | |
407 (defun rng-validate-clear () | |
408 (rng-validate-mode 1 t)) | |
409 | |
410 ;; These two variables are dynamically bound and used | |
411 ;; to pass information between rng-validate-while-idle | |
412 ;; and rng-validate-while-idle-continue-p. | |
413 | |
414 (defvar rng-validate-display-point nil) | |
415 (defvar rng-validate-display-modified-p nil) | |
416 | |
417 (defun rng-validate-while-idle-continue-p () | |
418 ;; input-pending-p and sit-for run timers that are | |
419 ;; ripe. Binding timer-idle-list to nil prevents | |
420 ;; this. If we don't do this, then any ripe timers | |
421 ;; will get run, and we won't get any chance to | |
422 ;; validate until Emacs becomes idle again or until | |
423 ;; the other lower priority timers finish (which | |
424 ;; can take a very long time in the case of | |
425 ;; jit-lock). | |
426 (let ((timer-idle-list nil)) | |
427 (and (not (input-pending-p)) | |
428 ;; Fake rng-validate-up-to-date-end so that the mode line | |
429 ;; shows progress. Also use this to save point. | |
430 (let ((rng-validate-up-to-date-end (point))) | |
431 (goto-char rng-validate-display-point) | |
432 (when (not rng-validate-display-modified-p) | |
433 (restore-buffer-modified-p nil)) | |
434 (force-mode-line-update) | |
435 (let ((continue (sit-for 0))) | |
436 (goto-char rng-validate-up-to-date-end) | |
437 continue))))) | |
438 | |
439 ;; Calling rng-do-some-validation once with a continue-p function, as | |
440 ;; opposed to calling it repeatedly, helps on initial validation of a | |
441 ;; large buffer with lots of errors. The overlays for errors will all | |
442 ;; get added when rng-do-some-validation returns and won't slow the | |
443 ;; validation process down. | |
444 | |
445 (defun rng-validate-while-idle (buffer) | |
446 (with-current-buffer buffer | |
447 (if rng-validate-mode | |
448 (if (let ((rng-validate-display-point (point)) | |
449 (rng-validate-display-modified-p (buffer-modified-p))) | |
450 (rng-do-some-validation 'rng-validate-while-idle-continue-p)) | |
451 (force-mode-line-update) | |
452 (rng-validate-done)) | |
453 ;; must have done kill-all-local-variables | |
454 (rng-kill-timers)))) | |
455 | |
456 (defun rng-validate-quick-while-idle (buffer) | |
457 (with-current-buffer buffer | |
458 (if rng-validate-mode | |
459 (if (rng-do-some-validation) | |
460 (force-mode-line-update) | |
461 (rng-validate-done)) | |
462 ;; must have done kill-all-local-variables | |
463 (rng-kill-timers)))) | |
464 | |
465 (defun rng-validate-done () | |
466 (when (or (not (current-message)) | |
467 (rng-current-message-from-error-overlay-p)) | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
468 (rng-error-overlay-message (or (rng-error-overlay-after (point)) |
86361 | 469 (rng-error-overlay-after (1- (point)))))) |
470 (rng-cancel-timers) | |
471 (force-mode-line-update)) | |
472 | |
473 (defun rng-do-some-validation (&optional continue-p-function) | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
474 "Do some validation work. Return t if more to do, nil otherwise." |
86361 | 475 (save-excursion |
476 (save-restriction | |
477 (widen) | |
478 (nxml-with-invisible-motion | |
106307
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
479 (condition-case-no-debug err |
86361 | 480 (and (rng-validate-prepare) |
481 (let ((rng-dt-namespace-context-getter '(nxml-ns-get-context))) | |
482 (nxml-with-unmodifying-text-property-changes | |
483 (rng-do-some-validation-1 continue-p-function)))) | |
96361
a99299e4d2de
American English spelling fix.
Glenn Morris <rgm@gnu.org>
parents:
94666
diff
changeset
|
484 ;; errors signaled from a function run by an idle timer |
86361 | 485 ;; are ignored; if we don't catch them, validation |
486 ;; will get mysteriously stuck at a single place | |
487 (rng-compile-error | |
488 (message "Incorrect schema. %s" (nth 1 err)) | |
489 (rng-validate-mode 0) | |
490 nil) | |
491 (error | |
492 (message "Internal error in rng-validate-mode triggered at buffer position %d. %s" | |
493 (point) | |
494 (error-message-string err)) | |
495 (rng-validate-mode 0) | |
496 nil)))))) | |
497 | |
498 (defun rng-validate-prepare () | |
499 "Prepare to do some validation, initializing point and the state. | |
500 Return t if there is work to do, nil otherwise." | |
501 (cond ((= rng-validate-up-to-date-end (point-min)) | |
502 (rng-set-initial-state) | |
503 t) | |
504 ((= rng-validate-up-to-date-end (point-max)) | |
505 nil) | |
506 (t (let ((state (get-text-property (1- rng-validate-up-to-date-end) | |
507 'rng-state))) | |
508 (cond (state | |
509 (rng-restore-state state) | |
510 (goto-char rng-validate-up-to-date-end)) | |
511 (t | |
512 (let ((pos (previous-single-property-change | |
513 rng-validate-up-to-date-end | |
514 'rng-state))) | |
515 (cond (pos | |
516 (rng-restore-state | |
517 (or (get-text-property (1- pos) 'rng-state) | |
518 (error "Internal error: state null"))) | |
519 (goto-char pos)) | |
520 (t (rng-set-initial-state)))))))))) | |
521 | |
111782
49c747159b30
* lisp/nxml/nxml-mode.el (nxml-parent-document): Add a variable.
Sam Steingold <sds@gnu.org>
parents:
106815
diff
changeset
|
522 (defun rng-dtd-trivial-p (dtd) |
49c747159b30
* lisp/nxml/nxml-mode.el (nxml-parent-document): Add a variable.
Sam Steingold <sds@gnu.org>
parents:
106815
diff
changeset
|
523 "Check whether the current dtd is different from the trivial default." |
49c747159b30
* lisp/nxml/nxml-mode.el (nxml-parent-document): Add a variable.
Sam Steingold <sds@gnu.org>
parents:
106815
diff
changeset
|
524 (or (null dtd) (eq dtd xmltok-predefined-entity-alist))) |
86361 | 525 |
526 (defun rng-do-some-validation-1 (&optional continue-p-function) | |
527 (let ((limit (+ rng-validate-up-to-date-end | |
528 rng-validate-chunk-size)) | |
529 (remove-start rng-validate-up-to-date-end) | |
530 (next-cache-point (+ (point) rng-state-cache-distance)) | |
531 (continue t) | |
532 (xmltok-dtd rng-dtd) | |
533 have-remaining-chars | |
534 xmltok-type | |
535 xmltok-start | |
536 xmltok-name-colon | |
537 xmltok-name-end | |
538 xmltok-replacement | |
539 xmltok-attributes | |
540 xmltok-namespace-attributes | |
541 xmltok-dependent-regions | |
542 xmltok-errors) | |
543 (when (= (point) 1) | |
544 (let ((regions (xmltok-forward-prolog))) | |
545 (rng-clear-overlays 1 (point)) | |
546 (while regions | |
547 (when (eq (aref (car regions) 0) 'encoding-name) | |
548 (rng-process-encoding-name (aref (car regions) 1) | |
549 (aref (car regions) 2))) | |
550 (setq regions (cdr regions)))) | |
551 (unless (equal rng-dtd xmltok-dtd) | |
552 (rng-clear-conditional-region)) | |
553 (setq rng-dtd xmltok-dtd)) | |
554 (while continue | |
555 (setq have-remaining-chars (rng-forward)) | |
556 (let ((pos (point))) | |
557 (setq continue | |
558 (and have-remaining-chars | |
559 (or (< pos limit) | |
560 (and continue-p-function | |
561 (funcall continue-p-function) | |
562 (setq limit (+ limit rng-validate-chunk-size)) | |
563 t)))) | |
564 (cond ((and rng-conditional-up-to-date-start | |
565 ;; > because we are getting the state from (1- pos) | |
566 (> pos rng-conditional-up-to-date-start) | |
567 (< pos rng-conditional-up-to-date-end) | |
568 (rng-state-matches-current (get-text-property (1- pos) | |
569 'rng-state))) | |
570 (when (< remove-start (1- pos)) | |
571 (rng-clear-cached-state remove-start (1- pos))) | |
572 ;; sync up with cached validation state | |
573 (setq continue nil) | |
574 ;; do this before settting rng-validate-up-to-date-end | |
575 ;; in case we get a quit | |
576 (rng-mark-xmltok-errors) | |
577 (rng-mark-xmltok-dependent-regions) | |
578 (setq rng-validate-up-to-date-end | |
579 (marker-position rng-conditional-up-to-date-end)) | |
580 (rng-clear-conditional-region) | |
581 (setq have-remaining-chars | |
582 (< rng-validate-up-to-date-end (point-max)))) | |
583 ((or (>= pos next-cache-point) | |
584 (not continue)) | |
585 (setq next-cache-point (+ pos rng-state-cache-distance)) | |
586 (rng-clear-cached-state remove-start pos) | |
587 (when have-remaining-chars | |
588 (rng-cache-state (1- pos))) | |
589 (setq remove-start pos) | |
590 (unless continue | |
591 ;; if we have just blank chars skip to the end | |
592 (when have-remaining-chars | |
593 (skip-chars-forward " \t\r\n") | |
594 (when (= (point) (point-max)) | |
595 (rng-clear-overlays pos (point)) | |
596 (rng-clear-cached-state pos (point)) | |
597 (setq have-remaining-chars nil) | |
598 (setq pos (point)))) | |
599 (when (not have-remaining-chars) | |
600 (rng-process-end-document)) | |
601 (rng-mark-xmltok-errors) | |
602 (rng-mark-xmltok-dependent-regions) | |
603 (setq rng-validate-up-to-date-end pos) | |
604 (when rng-conditional-up-to-date-end | |
605 (cond ((<= rng-conditional-up-to-date-end pos) | |
606 (rng-clear-conditional-region)) | |
607 ((< rng-conditional-up-to-date-start pos) | |
608 (set-marker rng-conditional-up-to-date-start | |
609 pos))))))))) | |
610 have-remaining-chars)) | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
611 |
86361 | 612 (defun rng-clear-conditional-region () |
613 (when rng-conditional-up-to-date-start | |
614 (set-marker rng-conditional-up-to-date-start nil) | |
615 (setq rng-conditional-up-to-date-start nil)) | |
616 (when rng-conditional-up-to-date-end | |
617 (set-marker rng-conditional-up-to-date-end nil) | |
618 (setq rng-conditional-up-to-date-end nil))) | |
619 | |
620 (defun rng-clear-cached-state (start end) | |
621 "Clear cached state between START and END." | |
622 (remove-text-properties start end '(rng-state nil))) | |
623 | |
624 (defun rng-cache-state (pos) | |
625 "Save the current state in a text property on the character at pos." | |
626 (put-text-property pos | |
627 (1+ pos) | |
628 'rng-state | |
629 (rng-get-state))) | |
630 | |
631 (defun rng-state-matches-current (state) | |
632 (and state | |
633 (rng-match-state-equal (car state)) | |
634 (nxml-ns-state-equal (nth 1 state)) | |
635 (equal (nth 2 state) rng-open-elements))) | |
636 | |
637 (defun rng-get-state () | |
638 (list (rng-match-state) | |
639 (nxml-ns-state) | |
640 rng-open-elements)) | |
641 | |
642 (defun rng-restore-state (state) | |
643 (rng-set-match-state (car state)) | |
644 (setq state (cdr state)) | |
645 (nxml-ns-set-state (car state)) | |
646 (setq rng-open-elements (cadr state)) | |
647 (setq rng-pending-contents nil) | |
648 (setq rng-collecting-text (rng-match-text-typed-p))) | |
649 | |
650 (defun rng-set-initial-state () | |
651 (nxml-ns-init) | |
652 (rng-match-start-document) | |
653 (setq rng-open-elements nil) | |
654 (setq rng-pending-contents nil) | |
655 (goto-char (point-min))) | |
656 | |
657 (defun rng-clear-overlays (beg end) | |
658 (unless rng-parsing-for-state | |
659 (let ((overlays (overlays-in beg end))) | |
660 (while overlays | |
661 (let* ((overlay (car overlays)) | |
662 (category (overlay-get overlay 'category))) | |
663 (cond ((eq category 'rng-error) | |
664 (let ((inhibit-quit t)) | |
665 (when (eq overlay rng-message-overlay) | |
666 (rng-error-overlay-message nil)) | |
667 (delete-overlay overlay) | |
668 ;; rng-error-count could be nil | |
669 ;; if overlays left over from a previous use | |
670 ;; of rng-validate-mode that ended with a change of mode | |
671 (when rng-error-count | |
672 (setq rng-error-count (1- rng-error-count))))) | |
673 ((and (eq category 'rng-dependent) | |
674 (<= beg (overlay-start overlay))) | |
675 (delete-overlay overlay)))) | |
676 (setq overlays (cdr overlays)))))) | |
677 | |
678 ;;; Dependent regions | |
679 | |
680 (defun rng-mark-xmltok-dependent-regions () | |
681 (while xmltok-dependent-regions | |
682 (apply 'rng-mark-xmltok-dependent-region | |
683 (car xmltok-dependent-regions)) | |
684 (setq xmltok-dependent-regions | |
685 (cdr xmltok-dependent-regions)))) | |
686 | |
687 (defun rng-mark-xmltok-dependent-region (fun start end &rest args) | |
688 (let ((overlay (make-overlay start end nil t t))) | |
689 (overlay-put overlay 'category 'rng-dependent) | |
690 (overlay-put overlay 'rng-funargs (cons fun args)))) | |
691 | |
692 (put 'rng-dependent 'evaporate t) | |
693 (put 'rng-dependent 'modification-hooks '(rng-dependent-region-changed)) | |
694 (put 'rng-dependent 'insert-behind-hooks '(rng-dependent-region-changed)) | |
695 | |
696 (defun rng-dependent-region-changed (overlay | |
697 after-p | |
698 change-start | |
699 change-end | |
700 &optional pre-change-length) | |
701 (when (and after-p | |
702 ;; Emacs sometimes appears to call deleted overlays | |
703 (overlay-start overlay) | |
704 (let ((funargs (overlay-get overlay 'rng-funargs))) | |
705 (save-match-data | |
706 (save-excursion | |
707 (save-restriction | |
708 (widen) | |
709 (apply (car funargs) | |
710 (append (list change-start | |
711 change-end | |
712 pre-change-length | |
713 (overlay-start overlay) | |
714 (overlay-end overlay)) | |
715 (cdr funargs)))))))) | |
716 (rng-after-change-function (overlay-start overlay) | |
717 change-end | |
718 (+ pre-change-length | |
719 (- (overlay-start overlay) | |
720 change-start))) | |
721 (delete-overlay overlay))) | |
722 | |
723 ;;; Error state | |
724 | |
725 (defun rng-mark-xmltok-errors () | |
726 (while xmltok-errors | |
727 (let ((err (car xmltok-errors))) | |
728 (rng-mark-not-well-formed (xmltok-error-message err) | |
729 (xmltok-error-start err) | |
730 (xmltok-error-end err))) | |
731 (setq xmltok-errors (cdr xmltok-errors)))) | |
732 | |
733 (defun rng-mark-invalid (message beg end) | |
734 (rng-mark-error message beg end)) | |
735 | |
736 (defun rng-mark-not-well-formed (message beg end) | |
737 ;; Don't try to validate further | |
738 ;;(rng-set-match-state rng-not-allowed-ipattern) | |
739 (rng-mark-error message beg end)) | |
740 | |
741 (defun rng-mark-error (message beg end) | |
742 (unless rng-parsing-for-state | |
743 (let ((overlays (overlays-in beg end))) | |
744 (while (and overlays message) | |
745 (let ((o (car overlays))) | |
746 (when (and (eq (overlay-get o 'category) 'rng-error) | |
747 (= (overlay-start o) beg) | |
748 (= (overlay-end o) end)) | |
749 (overlay-put o | |
750 'help-echo | |
751 (concat (overlay-get o 'help-echo) | |
752 "\n" | |
753 message)) | |
754 (setq message nil))) | |
755 (setq overlays (cdr overlays)))) | |
756 (when message | |
757 (let ((inhibit-quit t)) | |
758 (setq rng-error-count (1+ rng-error-count)) | |
759 (let ((overlay | |
760 (make-overlay beg end nil t | |
761 ;; Need to make the rear delimiter advance | |
762 ;; with the front delimiter when the overlay | |
763 ;; is empty, otherwise the front delimiter | |
764 ;; will move past the rear delimiter. | |
765 (= beg end)))) | |
766 ;; Ensure when we have two overlapping messages, the help-echo | |
767 ;; of the one that starts first is shown | |
768 (overlay-put overlay 'priority beg) | |
769 (overlay-put overlay 'category 'rng-error) | |
770 (overlay-put overlay 'help-echo message)))))) | |
771 | |
87346
c5910db8e06e
(rng-error): Rename from rng-error-face.
Jason Rumney <jasonr@gnu.org>
parents:
86555
diff
changeset
|
772 (put 'rng-error 'face 'rng-error) |
86361 | 773 (put 'rng-error 'modification-hooks '(rng-error-modified)) |
774 | |
775 ;; If we don't do this, then the front delimiter can move | |
776 ;; past the end delimiter. | |
777 (defun rng-error-modified (overlay after-p beg end &optional pre-change-len) | |
778 (when (and after-p | |
779 (overlay-start overlay) ; check not deleted | |
780 (>= (overlay-start overlay) | |
781 (overlay-end overlay))) | |
782 (let ((inhibit-quit t)) | |
783 (delete-overlay overlay) | |
784 (setq rng-error-count (1- rng-error-count))))) | |
785 | |
786 (defun rng-echo-area-clear-function () | |
787 (setq rng-message-overlay-current nil)) | |
788 | |
789 ;;; Error navigation | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
790 |
86361 | 791 (defun rng-maybe-echo-error-at-point () |
792 (when (or (not (current-message)) | |
793 (rng-current-message-from-error-overlay-p)) | |
794 (rng-error-overlay-message (rng-error-overlay-after (point))))) | |
795 | |
796 (defun rng-error-overlay-after (pos) | |
797 (let ((overlays (overlays-in pos (1+ pos))) | |
798 (best nil)) | |
799 (while overlays | |
800 (let ((overlay (car overlays))) | |
801 (when (and (eq (overlay-get overlay 'category) | |
802 'rng-error) | |
803 (or (not best) | |
804 (< (overlay-start best) | |
805 (overlay-start overlay)))) | |
806 (setq best overlay))) | |
807 (setq overlays (cdr overlays))) | |
808 best)) | |
809 | |
810 (defun rng-first-error () | |
811 "Go to the first validation error. | |
812 Turn on `rng-validate-mode' if it is not already on." | |
813 (interactive) | |
814 (or rng-validate-mode (rng-validate-mode)) | |
106307
cbe5e21da2e4
Try and remove assumptions about point-min==1.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
100908
diff
changeset
|
815 (rng-do-some-validation) |
86361 | 816 (let ((err (rng-find-next-error-overlay (1- (point-min))))) |
817 (if err | |
818 (rng-goto-error-overlay err) | |
819 (let ((pos (save-excursion | |
820 (goto-char (point-min)) | |
821 (rng-next-error 1)))) | |
822 (when pos | |
823 (goto-char pos)))))) | |
824 | |
825 (defun rng-mouse-first-error (event) | |
826 "Go to the first validation error from a mouse click." | |
827 (interactive "e") | |
828 (select-window (posn-window (event-start event))) | |
829 (rng-first-error)) | |
830 | |
831 (defun rng-next-error (arg) | |
832 "Go to the next validation error after point. | |
833 Turn on `rng-validate-mode' if it is not already on. | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
834 A prefix ARG specifies how many errors to move. |
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
835 A negative ARG moves backwards. Just \\[universal-argument] as a prefix |
86361 | 836 means goto the first error." |
837 (interactive "P") | |
838 (if (consp arg) | |
839 (rng-first-error) | |
840 (or rng-validate-mode (rng-validate-mode)) | |
841 (setq arg (prefix-numeric-value arg)) | |
842 (if (< arg 0) | |
843 (rng-previous-error-1 (- arg)) | |
844 (rng-next-error-1 arg)))) | |
845 | |
846 (defun rng-previous-error (arg) | |
847 "Go to the previous validation error before point. | |
848 Turn on `rng-validate-mode' if it is not already on. | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
849 A prefix ARG specifies how many errors to move. |
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
850 A negative ARG moves forwards. Just \\[universal-argument] as a prefix |
86361 | 851 means goto the first error." |
852 (interactive "P") | |
853 (if (consp arg) | |
854 (rng-first-error) | |
855 (or rng-validate-mode (rng-validate-mode)) | |
856 (setq arg (prefix-numeric-value arg)) | |
857 (if (< arg 0) | |
858 (rng-next-error-1 (- arg)) | |
859 (rng-previous-error-1 arg)))) | |
860 | |
861 (defun rng-next-error-1 (arg) | |
862 (let* ((pos (point)) | |
863 err last-err) | |
864 (while (and (> arg 0) | |
865 (setq err (rng-find-next-error-overlay pos))) | |
866 (setq arg (1- arg)) | |
867 (setq last-err err) | |
868 (setq pos (overlay-start err))) | |
869 (when (> arg 0) | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
870 (setq pos (max pos (1- rng-validate-up-to-date-end))) |
86361 | 871 (when (< rng-validate-up-to-date-end (point-max)) |
872 (message "Parsing...") | |
873 (while (let ((more-to-do (rng-do-some-validation))) | |
874 (while (and (> arg 0) | |
875 (setq err (rng-find-next-error-overlay pos))) | |
876 (setq arg (1- arg)) | |
877 (setq last-err err) | |
878 (setq pos (overlay-start err))) | |
879 (when (and (> arg 0) | |
880 more-to-do | |
881 (< rng-validate-up-to-date-end (point-max))) | |
882 ;; Display percentage validated. | |
883 (force-mode-line-update) | |
884 ;; Force redisplay but don't allow idle timers to run. | |
885 (let ((timer-idle-list nil)) | |
886 (sit-for 0)) | |
887 (setq pos | |
888 (max pos (1- rng-validate-up-to-date-end))) | |
889 t))))) | |
890 (if last-err | |
891 (rng-goto-error-overlay last-err) | |
892 (message "No more errors") | |
893 nil))) | |
894 | |
895 (defun rng-previous-error-1 (arg) | |
896 (let* ((pos (point)) | |
897 err last-err) | |
898 (while (and (> arg 0) | |
899 (setq err (rng-find-previous-error-overlay pos))) | |
900 (setq pos (overlay-start err)) | |
901 (setq last-err err) | |
902 (setq arg (1- arg))) | |
903 (when (and (> arg 0) | |
904 (< rng-validate-up-to-date-end (min pos (point-max)))) | |
905 (message "Parsing...") | |
906 (while (and (rng-do-some-validation) | |
907 (< rng-validate-up-to-date-end (min pos (point-max)))) | |
908 (force-mode-line-update) | |
909 ;; Force redisplay but don't allow idle timers to run. | |
910 (let ((timer-idle-list nil)) | |
911 (sit-for 0))) | |
912 (while (and (> arg 0) | |
913 (setq err (rng-find-previous-error-overlay pos))) | |
914 (setq pos (overlay-start err)) | |
915 (setq last-err err) | |
916 (setq arg (1- arg)))) | |
917 (if last-err | |
918 (rng-goto-error-overlay last-err) | |
919 (message "No previous errors") | |
920 nil))) | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
921 |
86361 | 922 (defun rng-goto-error-overlay (err) |
923 "Goto the start of error overlay ERR and print its message." | |
924 (goto-char (overlay-start err)) | |
925 (setq rng-message-overlay-inhibit-point nil) | |
926 (rng-error-overlay-message err)) | |
927 | |
928 (defun rng-error-overlay-message (err) | |
929 (if err | |
930 (unless (or (and (eq rng-message-overlay-inhibit-point (point)) | |
931 (eq rng-message-overlay err)) | |
932 (= (point-max) 1)) | |
933 (message "%s" (overlay-get err 'help-echo)) | |
934 (setq rng-message-overlay-current t) | |
935 (setq rng-message-overlay-inhibit-point (point))) | |
936 (when (rng-current-message-from-error-overlay-p) | |
937 (message nil)) | |
938 (setq rng-message-overlay-inhibit-point nil)) | |
939 (setq rng-message-overlay err)) | |
940 | |
941 (defun rng-current-message-from-error-overlay-p () | |
942 (and rng-message-overlay-current | |
943 rng-message-overlay | |
944 (equal (overlay-get rng-message-overlay 'help-echo) | |
945 (current-message)))) | |
946 | |
947 (defun rng-find-next-error-overlay (pos) | |
948 "Return the overlay for the next error starting after POS. | |
949 Return nil if there is no such overlay or it is out of date. | |
950 Do not do any additional validation." | |
951 (when rng-error-count | |
952 (let (done found overlays) | |
953 (while (not done) | |
954 (cond (overlays | |
955 (let ((overlay (car overlays))) | |
956 (setq overlays (cdr overlays)) | |
957 (when (and (eq (overlay-get overlay 'category) 'rng-error) | |
958 ;; Is it the first? | |
959 (= (overlay-start overlay) pos) | |
960 ;; Is it up to date? | |
961 (<= (overlay-end overlay) | |
962 rng-validate-up-to-date-end)) | |
963 (setq done t) | |
964 (setq found overlay)))) | |
965 ((or (= pos (point-max)) | |
966 (> (setq pos (next-overlay-change pos)) | |
967 rng-validate-up-to-date-end)) | |
968 (setq done t)) | |
969 (t (setq overlays (overlays-in pos (1+ pos)))))) | |
970 found))) | |
971 | |
972 (defun rng-find-previous-error-overlay (pos) | |
973 "Return the overlay for the last error starting before POS. | |
974 Return nil if there is no such overlay or it is out of date. | |
975 Do not do any additional validation." | |
976 (when (and rng-error-count | |
977 (<= pos rng-validate-up-to-date-end)) | |
978 (let (done found overlays) | |
979 (while (not done) | |
980 (cond (overlays | |
981 (let ((overlay (car overlays))) | |
982 (setq overlays (cdr overlays)) | |
983 (when (and (eq (overlay-get overlay 'category) 'rng-error) | |
984 ;; Is it the first? | |
985 (= (overlay-start overlay) pos)) | |
986 (setq done t) | |
987 (setq found overlay)))) | |
988 ((= pos (point-min)) | |
989 (setq done t)) | |
990 (t | |
991 (setq pos (previous-overlay-change pos)) | |
992 (setq overlays (overlays-in pos (1+ pos)))))) | |
993 found))) | |
994 | |
995 ;;; Parsing | |
996 | |
997 (defun rng-forward (&optional limit) | |
998 "Move forward over one or more tokens updating the state. | |
999 If LIMIT is nil, stop after tags. | |
1000 If LIMIT is non-nil, stop when end of last token parsed is >= LIMIT. | |
1001 Return nil at end of buffer, t otherwise." | |
1002 (let (type) | |
1003 (while (progn | |
1004 (setq type (xmltok-forward)) | |
1005 (rng-clear-overlays xmltok-start (point)) | |
1006 (let ((continue | |
1007 (cond ((eq type 'start-tag) | |
1008 (rng-process-start-tag 'start-tag) | |
1009 nil) | |
1010 ((eq type 'end-tag) | |
1011 (rng-process-end-tag) | |
1012 nil) | |
1013 ((eq type 'empty-element) | |
1014 (rng-process-start-tag 'empty-element) | |
1015 nil) | |
1016 ((eq type 'space) | |
1017 (rng-process-text xmltok-start nil t) | |
1018 t) | |
1019 ((eq type 'data) | |
1020 (rng-process-text xmltok-start nil nil) | |
1021 t) | |
1022 ((memq type '(entity-ref char-ref)) | |
1023 (cond (xmltok-replacement | |
1024 (rng-process-text xmltok-start | |
1025 nil | |
1026 'maybe | |
1027 xmltok-replacement)) | |
1028 ((eq type 'char-ref) | |
1029 (rng-process-unknown-char)) | |
1030 (t | |
1031 (rng-process-unknown-entity))) | |
1032 t) | |
1033 ((eq type 'cdata-section) | |
1034 (rng-process-text (+ xmltok-start 9) ; "<![CDATA[" | |
1035 (- (point) 3) ; "]]>" | |
1036 'maybe) | |
1037 t) | |
1038 ((eq type 'partial-start-tag) | |
1039 (rng-process-start-tag 'partial-start-tag) | |
1040 t) | |
1041 ((eq type 'partial-empty-element) | |
1042 (rng-process-start-tag 'empty-element) | |
1043 t) | |
1044 ((eq type 'partial-end-tag) | |
1045 (rng-process-end-tag 'partial) | |
1046 t) | |
1047 (t type)))) | |
1048 (if limit | |
1049 (< (point) limit) | |
1050 continue)))) | |
1051 (and type t))) | |
1052 | |
1053 (defun rng-process-start-tag (tag-type) | |
1054 "TAG-TYPE is `start-tag' for a start-tag, `empty-element' for | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
1055 an empty element. `partial-empty-element' should be passed |
86361 | 1056 as empty-element." |
1057 (and rng-collecting-text (rng-flush-text)) | |
1058 (setq rng-collecting-text nil) | |
1059 (setq rng-pending-contents nil) | |
1060 (rng-process-namespaces) | |
1061 (let ((tag (rng-process-tag-name))) | |
1062 (rng-process-attributes) | |
1063 ;; set the state appropriately | |
1064 (cond ((eq tag-type 'empty-element) | |
1065 (rng-process-start-tag-close) | |
1066 ;; deal with missing content with empty element | |
1067 (when (not (rng-match-empty-content)) | |
1068 (rng-match-after) | |
1069 (rng-mark-start-tag-close "Empty content not allowed")) | |
1070 (nxml-ns-pop-state)) | |
1071 ((eq tag-type 'start-tag) | |
1072 (rng-process-start-tag-close) | |
1073 (setq rng-collecting-text (rng-match-text-typed-p)) | |
1074 (rng-push-tag tag)) | |
1075 ((eq tag-type 'partial-start-tag) | |
1076 (rng-process-start-tag-close) | |
1077 (rng-match-after) | |
1078 (nxml-ns-pop-state))))) | |
1079 | |
1080 (defun rng-process-namespaces () | |
1081 (let ((nsatts xmltok-namespace-attributes) | |
1082 prefixes) | |
1083 (nxml-ns-push-state) | |
1084 (while nsatts | |
1085 (let* ((att (car nsatts)) | |
1086 (value (xmltok-attribute-value att))) | |
1087 (when value | |
1088 (let ((ns (nxml-make-namespace value)) | |
1089 (prefix (and (xmltok-attribute-prefix att) | |
1090 (xmltok-attribute-local-name att)))) | |
1091 (cond ((member prefix prefixes) | |
1092 (rng-mark-invalid "Duplicate namespace declaration" | |
1093 (xmltok-attribute-name-start att) | |
1094 (xmltok-attribute-name-end att))) | |
1095 ((not prefix) | |
1096 (nxml-ns-set-default ns)) | |
1097 (ns | |
1098 (nxml-ns-set-prefix prefix ns)) | |
1099 (t | |
1100 ;; cannot have xmlns:foo="" | |
1101 (rng-mark-invalid "Namespace prefix cannot be undeclared" | |
1102 (1- (xmltok-attribute-value-start att)) | |
1103 (1+ (xmltok-attribute-value-end att))))) | |
1104 (setq prefixes (cons prefix prefixes))))) | |
1105 (setq nsatts (cdr nsatts))))) | |
1106 | |
1107 (defun rng-process-tag-name () | |
1108 (let* ((prefix (xmltok-start-tag-prefix)) | |
1109 (local-name (xmltok-start-tag-local-name)) | |
1110 (name | |
1111 (if prefix | |
1112 (let ((ns (nxml-ns-get-prefix prefix))) | |
1113 (cond (ns (cons ns local-name)) | |
1114 ((and (setq ns | |
1115 (rng-match-infer-start-tag-namespace | |
1116 local-name)) | |
1117 (rng-match-start-tag-open (cons ns local-name))) | |
1118 (nxml-ns-set-prefix prefix ns) | |
1119 (rng-mark-start-tag-close "Missing xmlns:%s=\"%s\"" | |
1120 prefix | |
1121 (nxml-namespace-name ns)) | |
1122 nil) | |
1123 (t | |
1124 (rng-recover-bad-element-prefix) | |
1125 nil))) | |
1126 (cons (nxml-ns-get-default) local-name)))) | |
1127 (when (and name | |
1128 (not (rng-match-start-tag-open name))) | |
1129 (unless (and (not (car name)) | |
1130 (let ((ns (rng-match-infer-start-tag-namespace (cdr name)))) | |
1131 (and ns | |
1132 (rng-match-start-tag-open (cons ns local-name)) | |
1133 (progn | |
1134 (nxml-ns-set-default ns) | |
1135 ;; XXX need to check we don't have xmlns="" | |
1136 (rng-mark-start-tag-close "Missing xmlns=\"%s\"" | |
1137 (nxml-namespace-name ns)) | |
1138 t)))) | |
1139 (rng-recover-start-tag-open name))) | |
1140 (cons prefix local-name))) | |
1141 | |
1142 (defun rng-process-attributes () | |
1143 (let ((atts xmltok-attributes) | |
1144 names) | |
1145 (while atts | |
1146 (let* ((att (car atts)) | |
1147 (prefix (xmltok-attribute-prefix att)) | |
1148 (local-name (xmltok-attribute-local-name att)) | |
1149 (name | |
1150 (if prefix | |
1151 (let ((ns (nxml-ns-get-prefix prefix))) | |
1152 (and ns | |
1153 (cons ns local-name))) | |
1154 (cons nil local-name)))) | |
1155 (cond ((not name) | |
1156 (rng-recover-bad-attribute-prefix att)) | |
1157 ((member name names) | |
1158 (rng-recover-duplicate-attribute-name att)) | |
1159 ((not (rng-match-attribute-name name)) | |
1160 (rng-recover-attribute-name att)) | |
1161 ((rng-match-text-typed-p) | |
1162 (let ((value (xmltok-attribute-value att))) | |
1163 (if value | |
1164 (or (rng-match-attribute-value value) | |
1165 (rng-recover-attribute-value att)) | |
1166 (rng-match-after)))) | |
1167 (t (or (rng-match-end-tag) | |
1168 (error "Internal error:\ | |
1169 invalid on untyped attribute value")))) | |
1170 (setq names (cons name names))) | |
1171 (setq atts (cdr atts))))) | |
1172 | |
1173 (defun rng-process-start-tag-close () | |
1174 ;; deal with missing attributes | |
1175 (unless (rng-match-start-tag-close) | |
1176 (rng-mark-start-tag-close (rng-missing-attributes-message)) | |
1177 (rng-match-ignore-attributes))) | |
1178 | |
1179 (defun rng-mark-start-tag-close (&rest args) | |
1180 (when (not (eq xmltok-type 'partial-start-tag)) | |
1181 (rng-mark-invalid (apply 'format args) | |
1182 (- (point) | |
1183 (if (eq xmltok-type 'empty-element) | |
1184 2 | |
1185 1)) | |
1186 (point)))) | |
1187 | |
1188 (defun rng-recover-bad-element-prefix () | |
1189 (rng-mark-invalid "Prefix not declared" | |
1190 (1+ xmltok-start) | |
1191 xmltok-name-colon) | |
1192 (rng-match-unknown-start-tag-open)) | |
1193 | |
1194 (defun rng-recover-bad-attribute-prefix (att) | |
1195 (rng-mark-invalid "Prefix not declared" | |
1196 (xmltok-attribute-name-start att) | |
1197 (xmltok-attribute-name-colon att))) | |
1198 | |
1199 (defun rng-recover-duplicate-attribute-name (att) | |
1200 (rng-mark-invalid "Duplicate attribute" | |
1201 (xmltok-attribute-name-start att) | |
1202 (xmltok-attribute-name-end att))) | |
1203 | |
1204 (defun rng-recover-start-tag-open (name) | |
1205 (let ((required (rng-match-required-element-name))) | |
1206 (cond ((and required | |
1207 (rng-match-start-tag-open required) | |
1208 (rng-match-after) | |
1209 (rng-match-start-tag-open name)) | |
1210 (rng-mark-invalid (concat "Missing element " | |
1211 (rng-quote-string | |
1212 (rng-name-to-string required))) | |
1213 xmltok-start | |
1214 (1+ xmltok-start))) | |
1215 ((and (rng-match-optionalize-elements) | |
1216 (rng-match-start-tag-open name)) | |
1217 (rng-mark-invalid "Required elements missing" | |
1218 xmltok-start | |
1219 (1+ xmltok-start))) | |
1220 ((rng-match-out-of-context-start-tag-open name) | |
1221 (rng-mark-invalid "Element not allowed in this context" | |
1222 (1+ xmltok-start) | |
1223 xmltok-name-end)) | |
1224 (t | |
1225 (rng-match-unknown-start-tag-open) | |
1226 (rng-mark-invalid "Unknown element" | |
1227 (1+ xmltok-start) | |
1228 xmltok-name-end))))) | |
1229 | |
1230 (defun rng-recover-attribute-value (att) | |
1231 (let ((start (xmltok-attribute-value-start att)) | |
1232 (end (xmltok-attribute-value-end att))) | |
1233 (if (= start end) | |
1234 (rng-mark-invalid "Empty attribute value invalid" start (1+ end)) | |
1235 (rng-mark-invalid "Attribute value invalid" start end))) | |
1236 (rng-match-after)) | |
1237 | |
1238 (defun rng-recover-attribute-name (att) | |
1239 (rng-mark-invalid "Attribute not allowed" | |
1240 (xmltok-attribute-name-start att) | |
1241 (xmltok-attribute-name-end att))) | |
1242 | |
1243 (defun rng-missing-attributes-message () | |
1244 (let ((required-attributes | |
1245 (rng-match-required-attribute-names))) | |
1246 (cond ((not required-attributes) | |
1247 "Required attributes missing") | |
1248 ((not (cdr required-attributes)) | |
1249 (concat "Missing attribute " | |
1250 (rng-quote-string | |
1251 (rng-name-to-string (car required-attributes) t)))) | |
1252 (t | |
1253 (concat "Missing attributes " | |
1254 (mapconcat (lambda (nm) | |
1255 (rng-quote-string | |
1256 (rng-name-to-string nm t))) | |
1257 required-attributes | |
1258 ", ")))))) | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
1259 |
86361 | 1260 (defun rng-process-end-tag (&optional partial) |
1261 (cond ((not rng-open-elements) | |
1262 (rng-mark-not-well-formed "Extra end-tag" | |
1263 xmltok-start | |
1264 (point))) | |
1265 ((or partial | |
1266 (equal (cons (xmltok-end-tag-prefix) | |
1267 (xmltok-end-tag-local-name)) | |
1268 (car rng-open-elements))) | |
1269 (rng-end-element)) | |
1270 (t (rng-recover-mismatched-end-tag)))) | |
1271 | |
1272 (defun rng-end-element () | |
1273 (if rng-collecting-text | |
1274 (let ((contents (rng-contents-string))) | |
1275 (cond ((not contents) (rng-match-after)) | |
1276 ((not (rng-match-element-value contents)) | |
1277 (let* ((region (rng-contents-region))) | |
1278 (if (not region) | |
1279 (rng-mark-invalid "Empty content not allowed" | |
1280 xmltok-start | |
1281 (+ xmltok-start 2)) | |
1282 (rng-mark-invalid "Invalid data" | |
1283 (car region) | |
1284 (cdr region)))) | |
1285 (rng-match-after))) | |
1286 (setq rng-collecting-text nil) | |
1287 (setq rng-pending-contents nil)) | |
1288 (unless (rng-match-end-tag) | |
1289 (rng-mark-invalid (rng-missing-element-message) | |
1290 xmltok-start | |
1291 (+ xmltok-start 2)) | |
1292 (rng-match-after))) | |
1293 (nxml-ns-pop-state) | |
1294 (when (eq (car rng-open-elements) t) | |
1295 (rng-pop-tag)) | |
1296 (rng-pop-tag)) | |
1297 | |
1298 (defun rng-missing-element-message () | |
1299 (let ((element (rng-match-required-element-name))) | |
1300 (if element | |
1301 (concat "Missing element " | |
1302 (rng-quote-string (rng-name-to-string element))) | |
1303 "Required child elements missing"))) | |
1304 | |
1305 (defun rng-recover-mismatched-end-tag () | |
1306 (let* ((name (cons (xmltok-end-tag-prefix) | |
1307 (xmltok-end-tag-local-name)))) | |
1308 (cond ((member name (cdr rng-open-elements)) | |
1309 (let* ((suppress-error (eq (car rng-open-elements) t)) | |
1310 missing top) | |
1311 (while (progn | |
1312 (setq top (car rng-open-elements)) | |
1313 (rng-pop-tag) | |
1314 (unless (eq top t) | |
1315 (setq missing (cons top missing)) | |
1316 (nxml-ns-pop-state) | |
1317 (rng-match-after)) | |
1318 (not (equal top name)))) | |
1319 (unless suppress-error | |
1320 (rng-mark-missing-end-tags (cdr missing))))) | |
1321 ((rng-match-empty-before-p) | |
1322 (rng-mark-mismatched-end-tag) | |
1323 (rng-end-element)) | |
1324 (t (rng-mark-mismatched-end-tag) | |
1325 (setq rng-open-elements | |
1326 (cons t rng-open-elements)))))) | |
1327 | |
1328 (defun rng-mark-missing-end-tags (missing) | |
1329 (rng-mark-not-well-formed | |
1330 (format "Missing end-tag%s %s" | |
1331 (if (null (cdr missing)) "" "s") | |
1332 (mapconcat (lambda (name) | |
1333 (rng-quote-string | |
1334 (if (car name) | |
1335 (concat (car name) | |
1336 ":" | |
1337 (cdr name)) | |
1338 (cdr name)))) | |
1339 missing | |
1340 ", ")) | |
1341 xmltok-start | |
1342 (+ xmltok-start 2))) | |
1343 | |
1344 (defun rng-mark-mismatched-end-tag () | |
1345 (rng-mark-not-well-formed "Mismatched end-tag" | |
1346 (+ xmltok-start 2) | |
1347 xmltok-name-end)) | |
1348 | |
1349 (defun rng-push-tag (prefix-local-name) | |
1350 (setq rng-open-elements | |
1351 (cons prefix-local-name rng-open-elements))) | |
1352 | |
1353 (defun rng-pop-tag () | |
1354 (setq rng-open-elements (cdr rng-open-elements))) | |
1355 | |
1356 (defun rng-contents-string () | |
1357 (let ((contents rng-pending-contents)) | |
1358 (cond ((not contents) "") | |
1359 ((memq nil contents) nil) | |
1360 ((not (cdr contents)) | |
1361 (rng-segment-string (car contents))) | |
1362 (t (apply 'concat | |
1363 (nreverse (mapcar 'rng-segment-string | |
1364 contents))))))) | |
1365 | |
1366 (defun rng-segment-string (segment) | |
1367 (or (car segment) | |
1368 (apply 'buffer-substring-no-properties | |
1369 (cdr segment)))) | |
1370 | |
1371 (defun rng-segment-blank-p (segment) | |
1372 (if (car segment) | |
1373 (rng-blank-p (car segment)) | |
1374 (apply 'rng-region-blank-p | |
1375 (cdr segment)))) | |
1376 | |
1377 (defun rng-contents-region () | |
1378 (if (null rng-pending-contents) | |
1379 nil | |
1380 (let* ((contents rng-pending-contents) | |
1381 (head (cdar contents)) | |
1382 (start (car head)) | |
1383 (end (cadr head))) | |
1384 (while (setq contents (cdr contents)) | |
1385 (setq start (car (cdar contents)))) | |
1386 (cons start end)))) | |
1387 | |
1388 (defun rng-process-text (start end whitespace &optional value) | |
1389 "Process characters between position START and END as text. | |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
1390 END nil means point. WHITESPACE t means known to be whitespace, nil |
86361 | 1391 means known not to be, anything else means unknown whether whitespace |
96496
e374c747704b
Fix typos, and general docstring cleanup.
Juanma Barranquero <lekktu@gmail.com>
parents:
96361
diff
changeset
|
1392 or not. END must not be nil if WHITESPACE is neither t nor nil. |
86361 | 1393 VALUE is a string or nil; nil means the value is equal to the |
1394 string between START and END." | |
1395 (cond (rng-collecting-text | |
1396 (setq rng-pending-contents (cons (list value start (or end (point))) | |
1397 rng-pending-contents))) | |
1398 ((not (or (and whitespace | |
1399 (or (eq whitespace t) | |
1400 (if value | |
1401 (rng-blank-p value) | |
1402 (rng-region-blank-p start end)))) | |
1403 (rng-match-mixed-text))) | |
1404 (rng-mark-invalid "Text not allowed" start (or end (point)))))) | |
1405 | |
1406 (defun rng-process-unknown-char () | |
1407 (when rng-collecting-text | |
1408 (setq rng-pending-contents | |
1409 (cons nil rng-pending-contents)))) | |
1410 | |
1411 (defun rng-process-unknown-entity () | |
1412 (rng-process-unknown-char) | |
1413 (rng-match-optionalize-elements)) | |
1414 | |
1415 (defun rng-region-blank-p (beg end) | |
1416 (save-excursion | |
1417 (goto-char beg) | |
1418 (= (skip-chars-forward " \n\r\t" end) | |
1419 (- end beg)))) | |
1420 | |
1421 (defun rng-flush-text () | |
1422 (while rng-pending-contents | |
1423 (let ((segment (car rng-pending-contents))) | |
1424 (unless (or (rng-segment-blank-p segment) | |
1425 (rng-match-mixed-text)) | |
1426 (let ((region (cdr segment))) | |
1427 (rng-mark-invalid "In this context text cannot be mixed with elements" | |
1428 (car region) | |
1429 (cadr region))))) | |
1430 (setq rng-pending-contents (cdr rng-pending-contents)))) | |
1431 | |
1432 (defun rng-process-end-document () | |
1433 ;; this is necessary to clear empty overlays at (point-max) | |
1434 (rng-clear-overlays (point) (point)) | |
1435 (let ((start (save-excursion | |
1436 (skip-chars-backward " \t\r\n") | |
1437 (point)))) | |
1438 (cond (rng-open-elements | |
1439 (unless (eq (car rng-open-elements) t) | |
1440 (rng-mark-not-well-formed "Missing end-tag" | |
1441 start | |
1442 (point)))) | |
1443 ((not (rng-match-nullable-p)) | |
1444 (rng-mark-not-well-formed "No document element" | |
1445 start | |
1446 (point)))))) | |
1447 | |
1448 (defun rng-process-encoding-name (beg end) | |
1449 (unless (let ((charset (buffer-substring-no-properties beg end))) | |
1450 (or (nxml-mime-charset-coding-system charset) | |
1451 (string= (downcase charset) "utf-16"))) | |
1452 (rng-mark-not-well-formed "Unsupported encoding" beg end))) | |
1453 | |
1454 (defun rng-name-to-string (name &optional attributep) | |
1455 (let ((ns (car name)) | |
1456 (local-name (cdr name))) | |
1457 (if (or (not ns) | |
1458 (and (not attributep) | |
1459 (eq (nxml-ns-get-default) ns))) | |
1460 local-name | |
1461 (let ((prefix (nxml-ns-prefix-for ns))) | |
1462 (if prefix | |
1463 (concat prefix ":" local-name) | |
1464 (concat "{" (symbol-name ns) "}" local-name)))))) | |
1465 | |
1466 (provide 'rng-valid) | |
1467 | |
1468 ;;; rng-valid.el ends here |