File: rng-valid.el.html
For usage information, see the documentation for rng-validate-mode.
This file provides a minor mode that continually validates a buffer against a RELAX NG schema. The validation state is used to support schema-sensitive editing as well as validation. Validation is performed while Emacs is idle. XML parsing is done using xmltok.el. This file is responsible for checking that end-tags match their start-tags. Namespace processing is handled by nxml-ns.el. The RELAX NG Compact Syntax schema is parsed into internal form by rng-cmpct.el. This internal form is described by rng-pttrn.el. Validation of the document by matching against this internal form is done by rng-match.el. Handling of W3C XML Schema datatypes is delegated by rng-match.el to rng-xsd.el. The minor mode is intended to be used in conjunction with the nxml major mode, but does not have to be.
The major responsibility of this file is to allow validation to happen incrementally. If a buffer has been validated and is then changed, we can often revalidate it without having to completely parse and validate it from start to end. As we parse and validate the buffer, we periodically cache the state. The state has three components: the stack of open elements, the namespace processing state and the RELAX NG validation state. The state is cached as the value of the rng-state text property on the closing greater-than of tags (but at intervals, not on every tag). We keep track of the position up to which cached state is known to be correct by adding a function to the buffer's after-change-functions. This is stored in the rng-validate-up-to-date-end variable. The first way in which we make validation incremental is obvious: we start validation from the first cached state before rng-validate-up-to-date-end.
To make this work efficiently, we have to be able to copy the current parsing and validation state efficiently. We do this by minimizing destructive changes to the objects storing the state. When state is changed, we use the old state to create new objects representing the new state rather than destructively modifying the objects representing the old state. Copying the state is just a matter of making a list of three objects, one for each component of the state; the three objects themselves can be shared and do not need to be copied.
There's one other idea that is used to make validation incremental. Suppose we have a buffer that's 4000 bytes long and suppose we validated it, caching state at positions 1000, 2000 and 3000. Now suppose we make a change at position 1500 inserting 100 characters. rng-validate-up-to-date-end will be changed to 1500. When Emacs becomes idle and we revalidate, validation will restart using the cached state at position 1000. However, we take advantage of the cached state beyond rng-validate-up-to-date-end as follows. When our validation reaches position 2100 (the current position of the character that was at 2000), we compare our current state with the cached state. If they are the same, then we can stop parsing immediately and set rng-validate-up-to-date-end to the end of the buffer: we already know that the state cached at position 3100 is correct. If they are not the same, then we have to continue parsing. After the change, but before revalidation, we call the region from 1600 to the end of the buffer "conditionally up-to-date".
As well as the cached parsing and validation state, we also keep track of the errors in the file. Errors are stored as overlays with a category of rng-error. The number of such overlays in the buffer must always be equal to rng-error-count.
Defined variables (16)
rng-conditional-up-to-date-end | Marker for the end of the conditionally up-to-date region. |
rng-conditional-up-to-date-start | Marker for the start of the conditionally up-to-date region. |
rng-error-count | Number of errors in the current buffer. |
rng-message-overlay | Overlay in this buffer whose ‘help-echo’ property was last printed. |
rng-message-overlay-current | Non-nil if ‘rng-message-overlay’ is still the current message. |
rng-message-overlay-inhibit-point | Position at which message from overlay should be inhibited. |
rng-open-elements | Stack of names of open elements represented as a list. |
rng-parsing-for-state | Non-nil means we are currently parsing just to compute the state. |
rng-pending-contents | Text content of current element that has yet to be processed. |
rng-state-cache-distance | Distance in characters between each parsing and validation state cache. |
rng-validate-chunk-size | Number of characters in a RELAX NG validation chunk. |
rng-validate-delay | Time in seconds that Emacs must be idle before starting a full validation. |
rng-validate-mode | Non-nil if Rng-Validate mode is enabled. |
rng-validate-mode-hook | Hook run after entering or leaving ‘rng-validate-mode’. |
rng-validate-quick-delay | Time in seconds that Emacs must be idle before starting a quick validation. |
rng-validate-up-to-date-end | Last position where validation is known to be up to date. |
Defined functions (48)
Defined faces (1)
rng-error | Face for highlighting XML errors. |