1 package org.simantics.scl.ui.console;
\r
3 import gnu.trove.set.hash.THashSet;
\r
5 import java.util.ArrayList;
\r
7 import org.eclipse.core.runtime.IProgressMonitor;
\r
8 import org.eclipse.core.runtime.IStatus;
\r
9 import org.eclipse.core.runtime.Status;
\r
10 import org.eclipse.core.runtime.jobs.Job;
\r
11 import org.eclipse.jface.bindings.keys.KeyStroke;
\r
12 import org.eclipse.jface.bindings.keys.ParseException;
\r
13 import org.eclipse.jface.fieldassist.ContentProposalAdapter;
\r
14 import org.eclipse.swt.graphics.Color;
\r
15 import org.eclipse.swt.widgets.Composite;
\r
16 import org.osgi.framework.BundleContext;
\r
17 import org.osgi.framework.ServiceReference;
\r
18 import org.osgi.util.tracker.ServiceTracker;
\r
19 import org.simantics.scl.compiler.commands.CommandSession;
\r
20 import org.simantics.scl.compiler.commands.SCLConsoleListener;
\r
21 import org.simantics.scl.compiler.errors.CompilationError;
\r
22 import org.simantics.scl.compiler.errors.Locations;
\r
23 import org.simantics.scl.osgi.SCLOsgi;
\r
24 import org.simantics.scl.runtime.reporting.AbstractSCLReportingHandler;
\r
25 import org.simantics.scl.runtime.reporting.SCLReportingHandler;
\r
26 import org.simantics.scl.ui.Activator;
\r
27 import org.simantics.scl.ui.assist.SCLContentProposalProvider;
\r
28 import org.simantics.scl.ui.assist.StyledTextContentAdapter;
\r
31 * An SCL console with input and output area that can be embedded
\r
32 * into any editor or view.
\r
33 * @author Hannu Niemistö
\r
35 public class SCLConsole extends AbstractCommandConsole {
\r
36 public static final String JOB_NAME = "org.simantics.scl.console.job";
\r
38 private THashSet<Job> currentJobs = new THashSet<Job>();
\r
39 private Thread currentThread;
\r
40 private final IdentitySchedulingRule schedulingRule = new IdentitySchedulingRule();
\r
41 private ArrayList<SCLConsoleListener> listeners = new ArrayList<SCLConsoleListener>(2);
\r
42 private boolean consoleIsEmpty = true;
\r
44 SCLReportingHandler handler = new AbstractSCLReportingHandler() {
\r
46 public void print(String text) {
\r
47 appendOutput(text + "\n", null, null);
\r
50 public void printError(String error) {
\r
51 appendOutput(error + "\n", redColor, null);
\r
54 public void printCommand(String command) {
\r
55 appendOutput("> " + command.replace("\n", "\n ") + "\n", greenColor, null);
\r
59 CommandSession session = new CommandSession(SCLOsgi.MODULE_REPOSITORY, handler);
\r
60 ContentProposalAdapter contentProposalAdapter;
\r
62 public SCLConsole(Composite parent, int style) {
\r
63 super(parent, style);
\r
65 StyledTextContentAdapter styledTextContentAdapter = new StyledTextContentAdapter();
\r
66 SCLContentProposalProvider contentProvider = new SCLContentProposalProvider(session);
\r
69 contentProposalAdapter = new ContentProposalAdapter(
\r
71 styledTextContentAdapter,
\r
73 KeyStroke.getInstance("Ctrl+Space"),
\r
75 contentProposalAdapter.setAutoActivationDelay(200);
\r
76 } catch (ParseException e) {
\r
77 // No content assist then.
\r
80 addContributedListeners();
\r
84 protected boolean canExecuteCommand() {
\r
85 return !contentProposalAdapter.isProposalPopupOpen();
\r
89 public ErrorAnnotation[] validate(String command) {
\r
90 if(command.isEmpty())
\r
91 return ErrorAnnotation.EMPTY_ARRAY;
\r
93 CompilationError[] errors = session.validate(command);
\r
94 if(errors.length == 0)
\r
95 return ErrorAnnotation.EMPTY_ARRAY;
\r
97 ErrorAnnotation[] annotations = new ErrorAnnotation[errors.length];
\r
98 for(int i=0;i<errors.length;++i) {
\r
99 CompilationError error = errors[i];
\r
100 int begin = Locations.beginOf(error.location);
\r
101 if(begin == Integer.MAX_VALUE)
\r
103 int end = Locations.endOf(error.location);
\r
104 if(end == Integer.MIN_VALUE)
\r
105 end = command.length();
\r
113 annotations[i] = new ErrorAnnotation(begin, end, error.description);
\r
116 return annotations;
\r
119 private String jobNameFromCommand(String command) {
\r
120 return command.split("\n")[0];
\r
124 public void execute(final String command) {
\r
125 Job job = new Job(jobNameFromCommand(command)) {
\r
127 protected IStatus run(IProgressMonitor monitor) {
\r
129 synchronized(currentJobs) {
\r
130 currentJobs.remove(this);
\r
131 currentThread = Thread.currentThread();
\r
133 session.execute(command, handler);
\r
135 synchronized(currentJobs) {
\r
136 currentThread = null;
\r
137 if(currentJobs.isEmpty())
\r
138 for(SCLConsoleListener listener : listeners)
\r
139 listener.finishedExecution();
\r
142 return Status.OK_STATUS;
\r
145 job.setRule(schedulingRule);
\r
146 synchronized(currentJobs) {
\r
147 boolean firstJob = currentJobs.isEmpty();
\r
148 currentJobs.add(job);
\r
150 synchronized(listeners) {
\r
151 for(SCLConsoleListener listener : listeners)
\r
152 listener.startedExecution();
\r
159 public CommandSession getSession() {
\r
162 public void interruptCurrentCommands() {
\r
163 synchronized(currentJobs) {
\r
164 for(Job job : currentJobs)
\r
166 currentJobs.clear();
\r
167 if(currentThread != null)
\r
168 currentThread.interrupt();
\r
172 public void addListener(SCLConsoleListener listener) {
\r
173 synchronized (listeners) {
\r
174 listeners.add(listener);
\r
178 public void removeListener(SCLConsoleListener listener) {
\r
179 synchronized (listeners) {
\r
180 listeners.remove(listener);
\r
185 public void appendOutput(String text, Color foreground, Color background) {
\r
186 super.appendOutput(text, foreground, background);
\r
187 if(consoleIsEmpty) {
\r
188 consoleIsEmpty = false;
\r
189 synchronized (listeners) {
\r
190 for(SCLConsoleListener listener : listeners)
\r
191 listener.consoleIsNotEmptyAnymore();
\r
197 public void clear() {
\r
199 consoleIsEmpty = true;
\r
202 private void addContributedListeners() {
\r
203 final BundleContext context = Activator.getInstance().getBundle().getBundleContext();
\r
204 new ServiceTracker<SCLConsoleListener, SCLConsoleListener>(context,
\r
205 SCLConsoleListener.class, null) {
\r
207 public SCLConsoleListener addingService(
\r
208 ServiceReference<SCLConsoleListener> reference) {
\r
209 SCLConsoleListener listener = context.getService(reference);
\r
210 addListener(listener);
\r
215 public void modifiedService(
\r
216 ServiceReference<SCLConsoleListener> reference,
\r
217 SCLConsoleListener service) {
\r
221 public void removedService(
\r
222 ServiceReference<SCLConsoleListener> reference,
\r
223 SCLConsoleListener service) {
\r
224 removeListener(service);
\r