]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsole.java b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsole.java
new file mode 100755 (executable)
index 0000000..f227455
--- /dev/null
@@ -0,0 +1,228 @@
+package org.simantics.scl.ui.console;\r
+\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+import java.util.ArrayList;\r
+\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Status;\r
+import org.eclipse.core.runtime.jobs.Job;\r
+import org.eclipse.jface.bindings.keys.KeyStroke;\r
+import org.eclipse.jface.bindings.keys.ParseException;\r
+import org.eclipse.jface.fieldassist.ContentProposalAdapter;\r
+import org.eclipse.swt.graphics.Color;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.osgi.framework.BundleContext;\r
+import org.osgi.framework.ServiceReference;\r
+import org.osgi.util.tracker.ServiceTracker;\r
+import org.simantics.scl.compiler.commands.CommandSession;\r
+import org.simantics.scl.compiler.commands.SCLConsoleListener;\r
+import org.simantics.scl.compiler.errors.CompilationError;\r
+import org.simantics.scl.compiler.errors.Locations;\r
+import org.simantics.scl.osgi.SCLOsgi;\r
+import org.simantics.scl.runtime.reporting.AbstractSCLReportingHandler;\r
+import org.simantics.scl.runtime.reporting.SCLReportingHandler;\r
+import org.simantics.scl.ui.Activator;\r
+import org.simantics.scl.ui.assist.SCLContentProposalProvider;\r
+import org.simantics.scl.ui.assist.StyledTextContentAdapter;\r
+\r
+/**\r
+ * An SCL console with input and output area that can be embedded\r
+ * into any editor or view.\r
+ * @author Hannu Niemistö\r
+ */\r
+public class SCLConsole extends AbstractCommandConsole {\r
+       public static final String JOB_NAME = "org.simantics.scl.console.job";\r
+       \r
+       private THashSet<Job> currentJobs = new THashSet<Job>();\r
+       private Thread currentThread;\r
+       private final IdentitySchedulingRule schedulingRule = new IdentitySchedulingRule();\r
+       private ArrayList<SCLConsoleListener> listeners = new ArrayList<SCLConsoleListener>(2);\r
+       private boolean consoleIsEmpty = true;\r
+\r
+       SCLReportingHandler handler = new AbstractSCLReportingHandler() {\r
+        @Override\r
+        public void print(String text) {\r
+            appendOutput(text + "\n", null, null);\r
+        }\r
+        @Override\r
+        public void printError(String error) {\r
+            appendOutput(error + "\n", redColor, null);\r
+        }\r
+        @Override\r
+        public void printCommand(String command) {\r
+            appendOutput("> " + command.replace("\n", "\n  ") + "\n", greenColor, null);\r
+        }\r
+    };\r
+\r
+    CommandSession session = new CommandSession(SCLOsgi.MODULE_REPOSITORY, handler);\r
+    ContentProposalAdapter contentProposalAdapter;\r
+    \r
+    public SCLConsole(Composite parent, int style) {\r
+        super(parent, style);\r
+        \r
+        StyledTextContentAdapter styledTextContentAdapter = new StyledTextContentAdapter();\r
+        SCLContentProposalProvider contentProvider = new SCLContentProposalProvider(session);\r
+        \r
+        try {\r
+            contentProposalAdapter = new ContentProposalAdapter(\r
+                    input, \r
+                    styledTextContentAdapter, \r
+                    contentProvider, \r
+                    KeyStroke.getInstance("Ctrl+Space"), \r
+                    null);\r
+            contentProposalAdapter.setAutoActivationDelay(200);\r
+        } catch (ParseException e) {\r
+            // No content assist then.\r
+        }\r
+        \r
+        addContributedListeners();\r
+    }\r
+\r
+    @Override\r
+    protected boolean canExecuteCommand() {\r
+        return !contentProposalAdapter.isProposalPopupOpen();\r
+    }\r
+    \r
+    @Override\r
+    public ErrorAnnotation[] validate(String command) {\r
+        if(command.isEmpty())\r
+            return ErrorAnnotation.EMPTY_ARRAY;\r
+        \r
+        CompilationError[] errors = session.validate(command);\r
+        if(errors.length == 0)\r
+            return ErrorAnnotation.EMPTY_ARRAY;\r
+        \r
+        ErrorAnnotation[] annotations = new ErrorAnnotation[errors.length];\r
+        for(int i=0;i<errors.length;++i) {\r
+            CompilationError error = errors[i];\r
+            int begin = Locations.beginOf(error.location);\r
+            if(begin == Integer.MAX_VALUE)\r
+                begin = 0;\r
+            int end = Locations.endOf(error.location);\r
+            if(end == Integer.MIN_VALUE)\r
+                end = command.length();\r
+            if(begin == end) {\r
+                if(begin > 0)\r
+                    --begin;\r
+                else\r
+                    ++end;\r
+            }\r
+            \r
+            annotations[i] = new ErrorAnnotation(begin, end, error.description);\r
+        }\r
+        \r
+        return annotations;\r
+    }\r
+    \r
+    private String jobNameFromCommand(String command) {\r
+        return command.split("\n")[0];\r
+    }\r
+\r
+    @Override\r
+    public void execute(final String command) {\r
+        Job job = new Job(jobNameFromCommand(command)) {\r
+            @Override\r
+            protected IStatus run(IProgressMonitor monitor) {\r
+                try {\r
+                    synchronized(currentJobs) {\r
+                        currentJobs.remove(this);\r
+                        currentThread = Thread.currentThread();\r
+                    }\r
+                    session.execute(command, handler);\r
+                } finally {\r
+                    synchronized(currentJobs) {\r
+                        currentThread = null;\r
+                        if(currentJobs.isEmpty())\r
+                            for(SCLConsoleListener listener : listeners)\r
+                                listener.finishedExecution();\r
+                    }\r
+                }\r
+                return Status.OK_STATUS;\r
+            }\r
+        };\r
+        job.setRule(schedulingRule);\r
+        synchronized(currentJobs) {\r
+            boolean firstJob = currentJobs.isEmpty();\r
+            currentJobs.add(job);\r
+            if(firstJob) {\r
+                synchronized(listeners) {\r
+                    for(SCLConsoleListener listener : listeners)\r
+                        listener.startedExecution();\r
+                }\r
+            }\r
+        }\r
+        job.schedule();\r
+    }\r
+\r
+    public CommandSession getSession() {\r
+        return session;\r
+    }\r
+    public void interruptCurrentCommands() {\r
+        synchronized(currentJobs) {\r
+            for(Job job : currentJobs)\r
+                job.cancel();\r
+            currentJobs.clear();\r
+            if(currentThread != null)\r
+                currentThread.interrupt();\r
+        }\r
+    }\r
+    \r
+    public void addListener(SCLConsoleListener listener) {\r
+        synchronized (listeners) {\r
+            listeners.add(listener);\r
+        }\r
+    }\r
+    \r
+    public void removeListener(SCLConsoleListener listener) {\r
+        synchronized (listeners) {\r
+            listeners.remove(listener);\r
+        }\r
+    }\r
+    \r
+    @Override\r
+    public void appendOutput(String text, Color foreground, Color background) {\r
+        super.appendOutput(text, foreground, background);\r
+        if(consoleIsEmpty) {\r
+            consoleIsEmpty = false;\r
+            synchronized (listeners) {\r
+                for(SCLConsoleListener listener : listeners)\r
+                    listener.consoleIsNotEmptyAnymore();\r
+            }\r
+        }\r
+    }\r
+    \r
+    @Override\r
+    public void clear() {\r
+        super.clear();\r
+        consoleIsEmpty = true;\r
+    }\r
+\r
+    private void addContributedListeners() {\r
+        final BundleContext context = Activator.getInstance().getBundle().getBundleContext();\r
+        new ServiceTracker<SCLConsoleListener, SCLConsoleListener>(context,\r
+                SCLConsoleListener.class, null) {\r
+                    @Override\r
+                    public SCLConsoleListener addingService(\r
+                            ServiceReference<SCLConsoleListener> reference) {\r
+                        SCLConsoleListener listener = context.getService(reference);\r
+                        addListener(listener);\r
+                        return listener;\r
+                    }\r
+\r
+                    @Override\r
+                    public void modifiedService(\r
+                            ServiceReference<SCLConsoleListener> reference,\r
+                            SCLConsoleListener service) {\r
+                    }\r
+\r
+                    @Override\r
+                    public void removedService(\r
+                            ServiceReference<SCLConsoleListener> reference,\r
+                            SCLConsoleListener service) {\r
+                        removeListener(service);\r
+                    }\r
+                }.open();\r
+    }\r
+}\r