Source validation is a way to communicate errors, warnings and other information to the user "as-you-type" in the Structured Source Editor (SSE).
The SSE component allows clients to contribute their own custom validation to this feature via extension point. All that's required is an implementation of IValidator.
Create a new file.
To enable source validation, make sure you've checked the preference: Window > Preferences... > General > Text Editors > Structured Text Editors > Report problems as you type
Now type in the file. Depending on how your preferences are configured, this is done by drawing various colored "squiggles" where a suspected error appears in the editor.
These errors show up in the overview ruler as well. Clicking on these errors will move the cursor to that position in the editor.
If you hover the mouse over one of these squiggles or marks in the overview ruler, you'll get hover help with detailed info about the error/warning.
Clients can contribute their own custom validation to the source editor if they have an IValidator. All that's required is to specify the IValidator implementation, and for which content type/partitions it can operate.
Here's an example of how HTML Validator contributes to source validation via the extension point:
<extension point="org.eclipse.wst.sse.ui.sourcevalidation"> <validator scope="total" class="org.eclipse.wst.validation.html.HTMLValidator" id="org.eclipse.wst.validation.htmlsourcevalidator"> <contentTypeIdentifier id="org.eclipse.wst.html.core.htmlsource"> <partitionType id="org.eclipse.wst.html.HTML_DEFAULT"> </partitionType> </contentTypeIdentifier> <contentTypeIdentifier id="org.eclipse.jst.jsp.core.jspsource"> <partitionType id="org.eclipse.wst.html.HTML_DEFAULT"> </partitionType> </contentTypeIdentifier> </validator> </extension> |
So this example says "run the HTML Validator (a total scope validator) on files of HTML or JSP content type, on partitions of HTML_DEFAULT." Total scope means the validator analyzes the entire file every time it's invoked. This is used so the source validation framework can better optimize calls to this validator.
org.eclipse.core.runtime.ContentTypes
extension point.org.eclipse.jface.text.ITypedRegion#getType()
on which this as-you-type IValidator can operate. org.eclipse.wst.sse.core.text.IStructuredPartitions
org.eclipse.wst.xml.core.text.IXMLPartitions
org.eclipse.wst.html.core.text.IHTMLPartitions
org.eclipse.jst.jsp.core.text.IJSPPartitions
org.eclipse.wst.dtd.core.text.IDTDPartitions
org.eclipse.wst.css.core.text.ICSSPartitions
ISourceValidator
Since validating an entire document every time a user types is expensive, we've introduced the ISourceValidator interface.
First connect(IDocument)
is called to give the validator a reference to the document being
validated. The corresponding disconnect(IDocument)
is called when the Editor is closed,
the IDocument goes away, and the ISourceValidator won't be called anymore.
While connected to the Document, validate(IRegion, IValidationContext, IReporter)
will be called whenever the document has a dirty region. The ISourceValidator can then
optimize it's validation according to the dirty IRegion from the call.
This is an example of a simple validator. It looks for the first occurrence of the string "foo" in the dirty region and underlines it.
First create a pluging project called sourcevalidator.test
Make sure the bundle is a singleton, that is, the MANIFEST.MF file should contain this line:
Bundle-SymbolicName: sourcevalidator.test; singleton:=true
add this extension point description to the plugin.xml
<extension point="org.eclipse.wst.sse.ui.sourcevalidation"> <validator scope="total" class="sourcevalidator.test.FooValidator" id="sourcevalidator.test.FooValidator"> <contentTypeIdentifier id="org.eclipse.core.runtime.xml"> <partitionType id="org.eclipse.wst.xml.XML_DEFAULT"> </partitionType> </contentTypeIdentifier> </validator> </extension> |
create the class FooValidator.java
package sourcevalidator.test; import java.util.Locale; import org.eclipse.core.resources.IResource; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.wst.sse.ui.internal.reconcile.validator.ISourceValidator; import org.eclipse.wst.validation.internal.core.Message; import org.eclipse.wst.validation.internal.core.ValidationException; import org.eclipse.wst.validation.internal.provisional.core.IMessage; import org.eclipse.wst.validation.internal.provisional.core.IReporter; import org.eclipse.wst.validation.internal.provisional.core.IValidationContext; import org.eclipse.wst.validation.internal.provisional.core.IValidator; public class FooValidator implements ISourceValidator, IValidator { protected class LocalizedMessage extends Message { private String _message = null; public LocalizedMessage(int severity, String messageText) { this(severity, messageText, null); } public LocalizedMessage(int severity, String messageText, IResource targetObject) { this(severity, messageText, (Object) targetObject); } public LocalizedMessage(int severity, String messageText, Object targetObject) { super(null, severity, null); setLocalizedMessage(messageText); setTargetObject(targetObject); } public void setLocalizedMessage(String message) { _message = message; } public String getLocalizedMessage() { return _message; } public String getText() { return getLocalizedMessage(); } public String getText(ClassLoader cl) { return getLocalizedMessage(); } public String getText(Locale l) { return getLocalizedMessage(); } public String getText(Locale l, ClassLoader cl) { return getLocalizedMessage(); } } IDocument fDocument = null; public void connect(IDocument document) { fDocument = document; } public void disconnect(IDocument document) { fDocument = null; } /** * implement ISourceValidator */ public void validate(IRegion dirtyRegion, IValidationContext helper, IReporter reporter) { // look for foo int start = dirtyRegion.getOffset(); int length = dirtyRegion.getLength(); String dirtyText = fDocument.get().substring(start, start + length); int fooIndex = dirtyText.indexOf("foo"); if(fooIndex != -1) { IMessage m = new LocalizedMessage(IMessage.HIGH_SEVERITY, "found foo"); m.setOffset(start + fooIndex); m.setLength("foo".length()); try { m.setLineNo(fDocument.getLineOfOffset(start + fooIndex) + 1); } catch (BadLocationException e) { m.setLineNo(-1); } reporter.addMessage(this, m); } } public void cleanup(IReporter reporter) { // TODO Auto-generated method stub } public void validate(IValidationContext helper, IReporter reporter) throws ValidationException { // TODO Auto-generated method stub } } |
Now just start the workbench up and creat any *.xml file. Type "foo" and it should be underlined! Change it to "fo" and the squiggle should disappear.
Source Validation is often confused with Batch Workspace Validation. These are two different frameworks. They're invoked and displayed differently in the workbench (even if they use the same IValidator under the covers).
Source validation can be thought of as "as-you-type" validation, as errors/warnings show up in the editor as you type.
Batch Validation only occurs on save or build, or when explicitly invoked via the context menu in the Project Explorer. These errors not only show up in the editor, but also in the Problems View, and as little overlay icons on resources in the navigator views.
Batch validation adds markers to the resources in your workspace. this means that errors, warnings, and info messages will appear in the Problems View
Batch validation errors cause an icon to appear in the left hand ruler
Batch validation errors appear in some Navigator Views as little error overlay icons
If the same IValidator is used for source and batch validation, if a Batch Validation error is corrected in the "live" source editor, the icon on the left hand ruler will gray out, indicating that the problem has (probably) been fixed. When you save the file, the error should then disappear if the problem was in fact fixed.
Enablement Preferences
It would be useful to have ability to turn off certain validators. For example, maybe you want to turn off HTML validation for JSPs because you're only working on the JSP code sections at the moment."Partial Document" Validation
Partial document validation would be a great performance improvement (if a validator supports it).Other possible source validation: