]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsole.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.ui / src / org / simantics / scl / ui / console / SCLConsole.java
1 package org.simantics.scl.ui.console;\r
2 \r
3 import gnu.trove.set.hash.THashSet;\r
4 \r
5 import java.util.ArrayList;\r
6 \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
29 \r
30 /**\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
34  */\r
35 public class SCLConsole extends AbstractCommandConsole {\r
36         public static final String JOB_NAME = "org.simantics.scl.console.job";\r
37         \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
43 \r
44         SCLReportingHandler handler = new AbstractSCLReportingHandler() {\r
45         @Override\r
46         public void print(String text) {\r
47             appendOutput(text + "\n", null, null);\r
48         }\r
49         @Override\r
50         public void printError(String error) {\r
51             appendOutput(error + "\n", redColor, null);\r
52         }\r
53         @Override\r
54         public void printCommand(String command) {\r
55             appendOutput("> " + command.replace("\n", "\n  ") + "\n", greenColor, null);\r
56         }\r
57     };\r
58 \r
59     CommandSession session = new CommandSession(SCLOsgi.MODULE_REPOSITORY, handler);\r
60     ContentProposalAdapter contentProposalAdapter;\r
61     \r
62     public SCLConsole(Composite parent, int style) {\r
63         super(parent, style);\r
64         \r
65         StyledTextContentAdapter styledTextContentAdapter = new StyledTextContentAdapter();\r
66         SCLContentProposalProvider contentProvider = new SCLContentProposalProvider(session);\r
67         \r
68         try {\r
69             contentProposalAdapter = new ContentProposalAdapter(\r
70                     input, \r
71                     styledTextContentAdapter, \r
72                     contentProvider, \r
73                     KeyStroke.getInstance("Ctrl+Space"), \r
74                     null);\r
75             contentProposalAdapter.setAutoActivationDelay(200);\r
76         } catch (ParseException e) {\r
77             // No content assist then.\r
78         }\r
79         \r
80         addContributedListeners();\r
81     }\r
82 \r
83     @Override\r
84     protected boolean canExecuteCommand() {\r
85         return !contentProposalAdapter.isProposalPopupOpen();\r
86     }\r
87     \r
88     @Override\r
89     public ErrorAnnotation[] validate(String command) {\r
90         if(command.isEmpty())\r
91             return ErrorAnnotation.EMPTY_ARRAY;\r
92         \r
93         CompilationError[] errors = session.validate(command);\r
94         if(errors.length == 0)\r
95             return ErrorAnnotation.EMPTY_ARRAY;\r
96         \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
102                 begin = 0;\r
103             int end = Locations.endOf(error.location);\r
104             if(end == Integer.MIN_VALUE)\r
105                 end = command.length();\r
106             if(begin == end) {\r
107                 if(begin > 0)\r
108                     --begin;\r
109                 else\r
110                     ++end;\r
111             }\r
112             \r
113             annotations[i] = new ErrorAnnotation(begin, end, error.description);\r
114         }\r
115         \r
116         return annotations;\r
117     }\r
118     \r
119     private String jobNameFromCommand(String command) {\r
120         return command.split("\n")[0];\r
121     }\r
122 \r
123     @Override\r
124     public void execute(final String command) {\r
125         Job job = new Job(jobNameFromCommand(command)) {\r
126             @Override\r
127             protected IStatus run(IProgressMonitor monitor) {\r
128                 try {\r
129                     synchronized(currentJobs) {\r
130                         currentJobs.remove(this);\r
131                         currentThread = Thread.currentThread();\r
132                     }\r
133                     session.execute(command, handler);\r
134                 } finally {\r
135                     synchronized(currentJobs) {\r
136                         currentThread = null;\r
137                         if(currentJobs.isEmpty())\r
138                             for(SCLConsoleListener listener : listeners)\r
139                                 listener.finishedExecution();\r
140                     }\r
141                 }\r
142                 return Status.OK_STATUS;\r
143             }\r
144         };\r
145         job.setRule(schedulingRule);\r
146         synchronized(currentJobs) {\r
147             boolean firstJob = currentJobs.isEmpty();\r
148             currentJobs.add(job);\r
149             if(firstJob) {\r
150                 synchronized(listeners) {\r
151                     for(SCLConsoleListener listener : listeners)\r
152                         listener.startedExecution();\r
153                 }\r
154             }\r
155         }\r
156         job.schedule();\r
157     }\r
158 \r
159     public CommandSession getSession() {\r
160         return session;\r
161     }\r
162     public void interruptCurrentCommands() {\r
163         synchronized(currentJobs) {\r
164             for(Job job : currentJobs)\r
165                 job.cancel();\r
166             currentJobs.clear();\r
167             if(currentThread != null)\r
168                 currentThread.interrupt();\r
169         }\r
170     }\r
171     \r
172     public void addListener(SCLConsoleListener listener) {\r
173         synchronized (listeners) {\r
174             listeners.add(listener);\r
175         }\r
176     }\r
177     \r
178     public void removeListener(SCLConsoleListener listener) {\r
179         synchronized (listeners) {\r
180             listeners.remove(listener);\r
181         }\r
182     }\r
183     \r
184     @Override\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
192             }\r
193         }\r
194     }\r
195     \r
196     @Override\r
197     public void clear() {\r
198         super.clear();\r
199         consoleIsEmpty = true;\r
200     }\r
201 \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
206                     @Override\r
207                     public SCLConsoleListener addingService(\r
208                             ServiceReference<SCLConsoleListener> reference) {\r
209                         SCLConsoleListener listener = context.getService(reference);\r
210                         addListener(listener);\r
211                         return listener;\r
212                     }\r
213 \r
214                     @Override\r
215                     public void modifiedService(\r
216                             ServiceReference<SCLConsoleListener> reference,\r
217                             SCLConsoleListener service) {\r
218                     }\r
219 \r
220                     @Override\r
221                     public void removedService(\r
222                             ServiceReference<SCLConsoleListener> reference,\r
223                             SCLConsoleListener service) {\r
224                         removeListener(service);\r
225                     }\r
226                 }.open();\r
227     }\r
228 }\r