]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptAnnotationModel.java
Fixed SCLScriptAnnotationModel script validation threading
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / scl / scriptEditor / SCLScriptAnnotationModel.java
1 /*******************************************************************************
2  * Copyright (c) 2017 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     Semantum Oy - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.modeling.ui.scl.scriptEditor;
13
14 import java.util.Arrays;
15 import java.util.List;
16
17 import org.eclipse.core.runtime.IProgressMonitor;
18 import org.eclipse.core.runtime.IStatus;
19 import org.eclipse.core.runtime.Status;
20 import org.eclipse.core.runtime.jobs.Job;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.Position;
23 import org.eclipse.jface.text.source.Annotation;
24 import org.eclipse.jface.text.source.AnnotationModel;
25 import org.simantics.Simantics;
26 import org.simantics.db.procedure.Listener;
27 import org.simantics.scl.compiler.commands.CommandSession;
28 import org.simantics.scl.compiler.errors.CompilationError;
29 import org.simantics.scl.compiler.errors.ErrorSeverity;
30 import org.simantics.scl.compiler.errors.Locations;
31 import org.simantics.scl.compiler.module.repository.ModuleRepository;
32 import org.simantics.scl.runtime.reporting.AbstractSCLReportingHandler;
33 import org.simantics.scl.runtime.reporting.SCLReportingHandler;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * @author Tuukka Lehtonen
39  * @since 1.31.0
40  */
41 public class SCLScriptAnnotationModel extends AnnotationModel {
42
43     private static final Logger LOGGER = LoggerFactory.getLogger(SCLScriptAnnotationModel.class);
44
45     private final SCLScriptEditorInput input;
46     private final ModuleRepository repository;
47     private volatile boolean connected = false;
48
49     public SCLScriptAnnotationModel(SCLScriptEditorInput input, ModuleRepository repository) {
50         this.input = input;
51         this.repository = repository;
52     }
53
54     private Listener<String> sourceListener = new Listener<String>() {
55         @Override
56         public void execute(String result) {
57             if (connected && result != null)
58                 scheduleUpdateAnnotations(result);
59         }
60         @Override
61         public void exception(Throwable t) {
62             LOGGER.error("Failed to read SCL script source from " + input.getScriptURI(), t);
63         }
64         @Override
65         public boolean isDisposed() {
66             return !connected;
67         }
68     };
69
70     private void listenToSource() {
71         Simantics.getSession().asyncRequest(new ReadSCLScriptDefinition(input.getScriptURI()), sourceListener);
72     }
73
74     private static final SCLReportingHandler NOP = new AbstractSCLReportingHandler() {
75         @Override
76         public void print(String text) {}
77     };
78
79     private void scheduleUpdateAnnotations(String sourceText) {
80         //LOGGER.debug("scheduleUpdateAnnotations:\n" + sourceText);
81         Job validateJob = new Job("Validate Script") {
82             @Override
83             protected IStatus run(IProgressMonitor monitor) {
84                 updateAnnotations(sourceText);
85                 return Status.OK_STATUS;
86             }
87         };
88         validateJob.setPriority(Job.BUILD);
89         validateJob.setUser(false);
90         validateJob.setSystem(false);
91         validateJob.schedule();
92     }
93
94     private void updateAnnotations(String sourceText) {
95         //LOGGER.debug("updateAnnotations:\n" + sourceText);
96         CompilationError[] errors = new CommandSession(repository, NOP).validate(sourceText);
97         setAnnotations(Arrays.asList(errors));
98     }
99
100     protected void setAnnotations(List<CompilationError> errors) {
101         synchronized (getLockObject()) {
102             removeAllAnnotations();
103             for (CompilationError error : errors) {
104                 Annotation annotation = new Annotation(
105                         error.severity == ErrorSeverity.ERROR || error.severity == ErrorSeverity.IMPORT_ERROR ?
106                                 "org.eclipse.ui.workbench.texteditor.error" :
107                                     "org.eclipse.ui.workbench.texteditor.warning",
108                                     true, error.description);
109                 int begin = Locations.beginOf(error.location);
110                 int end = Locations.endOf(error.location);
111                 if (begin < 0 || end < begin) {
112                     begin = 0;
113                     end = 1;
114                 }
115                 addAnnotation(annotation, new Position(begin, end - begin));
116             }
117         }
118     }
119
120     @Override
121     public void connect(IDocument document) {
122         //LOGGER.debug("connect(" + document + ")");
123         super.connect(document);
124         connected = true;
125         listenToSource();
126     }
127
128     @Override
129     public void disconnect(IDocument document) {
130         //LOGGER.debug("disconnect(" + document + ")");
131         connected = false;
132         super.disconnect(document);
133     }
134
135 }