-package org.simantics.scl.ui.editor;
-
-
-import java.util.Collection;
-import java.util.Iterator;
-
-import org.eclipse.jface.resource.ImageRegistry;
-import org.eclipse.jface.text.Document;
-import org.eclipse.jface.text.ITextListener;
-import org.eclipse.jface.text.Position;
-import org.eclipse.jface.text.TextEvent;
-import org.eclipse.jface.text.source.Annotation;
-import org.eclipse.jface.text.source.AnnotationModel;
-import org.eclipse.jface.text.source.AnnotationPainter;
-import org.eclipse.jface.text.source.IAnnotationModel;
-import org.eclipse.jface.text.source.ISharedTextColors;
-import org.eclipse.jface.text.source.OverviewRuler;
-import org.eclipse.jface.text.source.SourceViewer;
-import org.eclipse.jface.text.source.VerticalRuler;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.KeyAdapter;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.RGB;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.simantics.scl.compiler.ErrorMessage;
-import org.simantics.scl.compiler.InvalidInputException;
-import org.simantics.scl.compiler.SCLCompiler;
-import org.simantics.scl.compiler.SCLCompilerConfiguration;
-
-public class SCLTextEditor extends Composite {
-
- private static final int DELAY_BEFORE_COMPILATION = 500 /*ms*/;
-
- SCLCompilerConfiguration configuration;
-
- SourceViewer viewer;
- ImageRegistry imageRegistry;
- SCLAnnotationAccess annotationAccess;
- ISharedTextColors sharedTextColors;
- IAnnotationModel annotationModel;
-
- public SCLTextEditor(Composite parent, int style, SCLCompilerConfiguration configuration) {
- super(parent, style);
- setLayout(new FillLayout());
-
- this.configuration = configuration;
-
- imageRegistry = new ImageRegistry(parent.getDisplay());
- annotationAccess = new SCLAnnotationAccess(imageRegistry);
- sharedTextColors = new SharedTextColors(getDisplay());
- annotationModel = new AnnotationModel();
-
- VerticalRuler leftRuler = new VerticalRuler(12, annotationAccess);
- leftRuler.setModel(annotationModel);
-
- OverviewRuler rightRuler =
- new OverviewRuler(annotationAccess, 12, sharedTextColors);
- rightRuler.setModel(annotationModel);
- rightRuler.addAnnotationType("error");
- rightRuler.setAnnotationTypeLayer("error", 0);
- rightRuler.setAnnotationTypeColor("error", sharedTextColors.getColor(new RGB(255,0,128)));
-
- viewer = new SourceViewer(this,
- leftRuler, rightRuler,
- true,
- SWT.H_SCROLL | SWT.V_SCROLL);
- Document document = new Document();
- viewer.setDocument(document, annotationModel);
- viewer.setEditable(true);
- viewer.configure(new SCLSourceViewerConfiguration(
- getDisplay(), sharedTextColors));
-
- // Annotations to text area
- AnnotationPainter annotationPainter =
- new AnnotationPainter(viewer, annotationAccess);
- annotationPainter.addAnnotationType("error");
- annotationPainter.setAnnotationTypeColor("error", sharedTextColors.getColor(new RGB(255,0,128)));
- viewer.addPainter(annotationPainter);
- annotationModel.addAnnotationModelListener(annotationPainter);
-
- // Undo support (maybe not needed in workbench?)
- viewer.getTextWidget().addKeyListener(new KeyAdapter() {
- @Override
- public void keyReleased(KeyEvent e) {
- }
- @Override
- public void keyPressed(KeyEvent e) {
- if(e.keyCode=='z'&& e.stateMask == SWT.CTRL) {
- viewer.getUndoManager().undo();
- }
- else if(e.keyCode=='y'&& e.stateMask == SWT.CTRL) {
- viewer.getUndoManager().redo();
- }
- }
- });
-
- // Automatic compilation when text changes
- viewer.addTextListener(new ITextListener() {
- @Override
- public void textChanged(TextEvent event) {
- scheduleCompilation();
- }
- });
- }
-
- @Override
- public void dispose() {
- super.dispose();
- sharedTextColors.dispose();
- }
-
- @SuppressWarnings("unchecked")
- private void removeAnnotations() {
- Iterator<Annotation> it = annotationModel.getAnnotationIterator();
- while(it.hasNext()) {
- Annotation annotation = it.next();
- annotationModel.removeAnnotation(annotation);
- }
- }
-
- private void setAnnotations(Collection<ErrorMessage> messages) {
- removeAnnotations();
- for(ErrorMessage message : messages) {
- annotationModel.addAnnotation(
- new Annotation("error", true, message.getMessage()),
- new Position(message.getStart(), message.getStop()-message.getStart()+1));
- }
- }
-
- /**
- * Tries to compile current
- */
- private void compileSync(String code) {
- try {
- SCLCompiler.compileExpression(configuration, code);
- getDisplay().asyncExec(new Runnable() {
- @Override
- public void run() {
- removeAnnotations();
- }
- });
- } catch (final InvalidInputException e) {
- getDisplay().asyncExec(new Runnable() {
- @Override
- public void run() {
- setAnnotations(e.getErrors());
- }
- });
- } catch(Exception e) {
- e.printStackTrace();
- }
- }
-
- Object compilationLock = new Object();
- String codeToBeCompiled;
-
- private synchronized void scheduleCompilation() {
- synchronized(compilationLock) {
- if(codeToBeCompiled == null) {
- new Thread("SCLTextEditor compilation") {
- public void run() {
- while(true) {
- String code;
- // Waits until code has remained unmodified for
- // time specified by DELAY_BEFORE_COMPILATION.
- synchronized(compilationLock) {
- do {
- code = codeToBeCompiled;
- try {
- compilationLock.wait(DELAY_BEFORE_COMPILATION);
- } catch (InterruptedException e) {
- }
- } while(!code.equals(codeToBeCompiled));
- }
-
- // Does the actual compilation and updates
- // annotations.
- compileSync(code);
-
- // If code was not modified during compilation,
- // exits the compilation thread and sets
- // codeToBeCompiled null to signal inactivity.
- synchronized(compilationLock) {
- if(code.equals(codeToBeCompiled)) {
- codeToBeCompiled = null;
- return;
- }
- }
- }
- }
- }.start();
- }
- codeToBeCompiled = viewer.getDocument().get();
- compilationLock.notify();
- }
- }
-
- public String getContent() {
- final String[] result = new String[1];
- getDisplay().syncExec(new Runnable() {
- @Override
- public void run() {
- result[0] = viewer.getDocument().get();
- }
- });
- return result[0];
- }
-
- public void setContent(final String content) {
- getDisplay().asyncExec(new Runnable() {
- @Override
- public void run() {
- if (viewer.getTextWidget().isDisposed()) return;
- viewer.getDocument().set(content);
- }
- });
- }
-
- private Point storedSelectedRange;
-
- public void storeSelectedRange() {
- storedSelectedRange = viewer.getSelectedRange();
- }
-
- public void restoreSelectedRange() {
- if (storedSelectedRange != null) {
- viewer.setSelectedRange(storedSelectedRange.x, storedSelectedRange.y);
- storedSelectedRange = null;
- }
- }
-
-}