Saturday, August 29, 2009

VM Arguments in Eclipse

Eclipse.ini
Eclipse.ini has been explained in detail here. It is used to control the Eclipse start up. This text file will contain the options that can also be provided from command line when invoking Eclipse.

Two of them are -vm and -vmargs. These and other such arguments have been explained here in detail.


-vm <path to java vm> (Executable, Main)
This is the path to the JRE/JDK which will be used to run Eclipse. Eclipse supports Java 1.42 and above. The path should be absolute. The path should point to the bin folder but can also point to java.exe, java lib folder or the Java VM execution environment description file (whatever that is). The path should follow  -vm and should one the separate line right after it.

-vm
C:\Program Files\IBM\Java50\bin

This path is copied to eclipse.vm and can be accessed at runtime using System.getProperty("eclipse.vm").


-vmargs [vmargs*] (Executable, Main)
These are arguments are passed as is to JVM. Used to configure JVM that would run Eclipse. This should be last argument in eclipse.ini as anything that follows it is passed to JVM and eclipse doesn't bothers about it. Again, the value is available as system property "eclipse.vmargs" at runtime.

A typical eclipse.ini will have -Xms and -Xmx following the -vmargs. They define the minimum and maximum heap size respectively. Again, each argument has to be defined on a separate line.


-vmargs
-Xms40m
-Xmx256m

This means the JVM launching Eclipse will have minimum heap size of 40 MB and a max of 256MB.

Target Definition
The target definition editor or wizard has an Arguments tab. This page has a section which deals with VM Arguments. The VM Arguments specified here are used to initialize the Run configurations. This section has an Import... button which produces an Import Arguments dialog. The import argument dialog scans the selected bundle containers and presents the VM Arguments from them. They do have no effect on build.

Run Configuration

The run configurations generally have an Arguments tab. This tab has a section for VM Arguments. Values specified here are sent to the JVM while launching.

The Eclipse Application Run Configuration defaults the VM Arguments from the active target platform.

Thursday, August 20, 2009

how do i install pde

PDE or Plug-in Development Environment is part of Eclipse SDK. If you have using Eclipde IDE for Java Developers or some other distribution like this then you will have only Eclipse Platform and not the SDK. The various distribution packages are listed here.

The SDK can be installed from the update site. The URL for Galeleo repository is Galileo - http://download.eclipse.org/releases/galileo. Use Help > Install new software... to install the new features to your existing eclipse installation.

Only PDE too can be installed. Open the Install (new software) wizard and use link mentioned above. Filter the results for "Eclipse plug-in development environment". The PDE will be available as "Eclipse plug-in development environment" under "General Purpose Tools" category.


Install wizard
And how to install Eclipse? Well, there is no installer. Just download it and unzip it wherever you wish on your hard disk. To uninstall, just delete it. Eclipse needs JRE (or JDK) 1.4.2 or above. So make sure one is available in your path settings.

Wednesday, August 19, 2009

Adding SpellChecking to custom editors

Eclipse provides a nice framework to use spell checking in dialog and editors. Chris has tipped about it here. However, if you are using a custom editor then you have to put few pieces together yourself. Consider an XML editor. We would want the spelling check only for the string in attribute values and not the XML Tags.

Let us try and implement this. We can start with the XML editor template provided by PDE.

1. Create a new plug-in using "Plug-in with an Editor" template.

New Plug-in Wizard
2.  This will create a simple XML Editor by extending TextEditor.

3. The XMLEditor uses XMLConfiguration to set the source viewer configuration.

public XMLEditor() {
 super();
 colorManager = new ColorManager();
 setSourceViewerConfiguration(new XMLConfiguration(colorManager));
 setDocumentProvider(new XMLDocumentProvider());
}

Modify the constructor for XMLConfiguration and pass the preference store. It will be needed by its super class.

public XMLEditor() {
 super();
 colorManager = new ColorManager();
 setSourceViewerConfiguration(new XMLConfiguration(colorManager, getPreferenceStore()));
 setDocumentProvider(new XMLDocumentProvider());
} 
 
4. The XMLConfiguration basically hooks various listeners, providers and assistants to the Editor. The template generated code will have it sub-classed from SourceViewerConfiguration. Change it to TextSourceViewerConfiguration. The TextSourceViewerConfiguration provides out of the box spell checker, spelling annotation, problem hover text, quick fixes, etc.

public class XMLConfiguration extends TextSourceViewerConfiguration { //SourceViewerConfiguration {
...
public XMLConfiguration(ColorManager colorManager, IPreferenceStore preferenceStore) {
 super(preferenceStore);
 this.colorManager = colorManager;
}
...

The preferenceStore will be used for checking dictionary and other preferences. They can be set from Window > Preferences > General > Editors > Text Editors > Spelling .

5. Override the getReconciler function. The implementation for getReconciler provided by TextSourceViewerConfiguration uses a SpellingReconcileStrategy. The SpellingReconcileStrategy will spell check the whole document. Since its an XML Editor, only quoted strings should be spell checked and the XML tags should be skipped.

/**
* Providing custom XMLSpellingReconcileStrategy to enable spell checking for only strings
*/
/* (non-Javadoc)
* @see org.eclipse.jface.text.source.SourceViewerConfiguration#getReconciler(org.eclipse.jface.text.source.ISourceViewer)
*/
public IReconciler getReconciler(ISourceViewer sourceViewer) {
 XMLSpellingReconcileStrategy strategy = new XMLSpellingReconcileStrategy(sourceViewer, EditorsUI.getSpellingService());
 Reconciler reconciler = new Reconciler();
 reconciler.setReconcilingStrategy(strategy, XMLStringPartitionScanner.XML_STRING);
 reconciler.setDocumentPartitioning(XMLStringPartitionScanner.XML_STRING);
 return reconciler;
}

6. XMLStringPartitionScanner will be our custom document partition scanner to identify the quoted string. The template generated code will make use of XMLPartitionScanner. This class specifies the rules for identifying the XML tags and comments. Since, the quoted string are part of XML Tag only, we can not use this partition scanner. Therefore, we write our custom document partition scanner and at supply it to the reconcile strategy.

public class XMLStringPartitionScanner extends RuleBasedPartitionScanner {

 public final static String XML_STRING = "__xml_string";

 public XMLStringPartitionScanner() {
  IToken stringToken = new Token(XML_STRING);
  IPredicateRule[] rules = new IPredicateRule[1];

  rules[0] = new MultiLineRule("\"", "\"", stringToken, '\\');
  setPredicateRules(rules);
 }
}

7. XMLSpellingReconcileStrategy will extend SpellingReconcileStrategy since it already knows how to collect spelling problem, etc. Only reconcile is what needs to be overridden.

public class XMLSpellingReconcileStrategy extends SpellingReconcileStrategy {

 public XMLSpellingReconcileStrategy(ISourceViewer sourceViewer, SpellingService spellingService) {
  super(sourceViewer, spellingService);
 }
 ...
 public void reconcile(IRegion region) {

  AbstractDocument document = (AbstractDocument) getDocument();
  IDocumentPartitioner docPartitioner = document.getDocumentPartitioner(XMLStringPartitionScanner.XML_STRING);

  IAnnotationModel model = getAnnotationModel();
  if (region.getOffset() == 0 && region.getLength() == document.getLength()) {
  //reconciling whole document
  super.reconcile(region);
  deleteUnwantedAnnotations();
  } else {
   //partial reconciliation
   //preserve spelling annotations first
   Iterator iter = model.getAnnotationIterator();
   Map spellingErrors = new HashMap(1);
   while (iter.hasNext()) {
    Annotation annotation = (Annotation) iter.next();
    if (annotation instanceof SpellingAnnotation) {
     SpellingAnnotation spellingAnnotation = (SpellingAnnotation) annotation;
     Position position = model.getPosition(spellingAnnotation);
     String contentType = docPartitioner.getContentType(position.getOffset());

     if (XMLStringPartitionScanner.XML_STRING.equalsIgnoreCase(contentType)) {
      spellingErrors.put(spellingAnnotation, model.getPosition(annotation));
     }
    }
   }

   //reconcile
   super.reconcile(region);

   //restore annotations
   model = getAnnotationModel();
   iter = spellingErrors.keySet().iterator();
   while (iter.hasNext()) {
    Annotation annotation = (Annotation) iter.next();
    model.addAnnotation(annotation, (Position) spellingErrors.get(annotation));
   }
   deleteUnwantedAnnotations();
  }

 }

 /**
 * Deletes the spelling annotations marked for XML Tags
 */
 private void deleteUnwantedAnnotations() {
  AbstractDocument document = (AbstractDocument) getDocument();
  IDocumentPartitioner docPartitioner = document.getDocumentPartitioner(XMLStringPartitionScanner.XML_STRING);
  IAnnotationModel model = getAnnotationModel();
  Iterator iter = model.getAnnotationIterator();

  while (iter.hasNext()) {
   Annotation annotation = (Annotation) iter.next();
   if (annotation instanceof SpellingAnnotation) {
    SpellingAnnotation spellingAnnotation = (SpellingAnnotation) annotation;
    Position position = model.getPosition(spellingAnnotation);
    String contentType = docPartitioner.getContentType(position.getOffset());
    if (!XMLStringPartitionScanner.XML_STRING.equalsIgnoreCase(contentType)) {
     model.removeAnnotation(spellingAnnotation);
    }
   }
  }
 }
}

8. Putting it all together

The XMLStringPartitionScanner is our document partition scanner. It uses the MultiLineRule to locate the quoted string. XMLDocumentProvider adds it to the XML document.

public class XMLDocumentProvider extends FileDocumentProvider {

 protected IDocument createDocument(Object element) throws CoreException {
  IDocument document = super.createDocument(element);
  if (document != null) {
   IDocumentPartitioner partitioner = new FastPartitioner(new XMLPartitionScanner(), new String[] {XMLPartitionScanner.XML_TAG, XMLPartitionScanner.XML_COMMENT});
   partitioner.connect(document);
   document.setDocumentPartitioner(partitioner);

   //Adding our string partition scanner to the document
   partitioner = new FastPartitioner(new XMLStringPartitionScanner(), new String[] {XMLStringPartitionScanner.XML_STRING});
   partitioner.connect(document);
   ((AbstractDocument) document).setDocumentPartitioner(XMLStringPartitionScanner.XML_STRING, partitioner);
  }
  return document;
 }
}

XMLPartitionScanner is generated by the template and it locates XML tags and comments. Since quoted strings are part of tags, we added XMLStringPartitionScanner too.

The XMLConfiguration finally wires all the content types to PresentationReconciler

9. After thoughts

All the infrastructure is already in place for enabling spell checking. But custom editors need some extra wiring. If finer control is needed on the quick fix assistant override getQuickAssistAssistant function and for controlling the hover message getTextHover will do the trick.

10. Source code


The archived project can be downloaded from here.

11. Disclaimer :-)

This code doesn't cover all the scenarios as it is just an example. These things I figured out while fixing the bug #286203. Feel free to add your suggestions and point out any mistakes you see.Eclipse provides a nice framework to use spell checking in dialog and editors. Chris has tipped about it here. However, if you are using a custom editor then you have to put few pieces together yourself. Consider an XML editor. We would want the spelling check only for the string in attribute values and not the XML Tags.