diff --git a/editor/org.processing.editor/.classpath b/editor/org.processing.editor/.classpath
new file mode 100644
index 000000000..8643519bb
--- /dev/null
+++ b/editor/org.processing.editor/.classpath
@@ -0,0 +1,15 @@
+
+
+ * Preprocesses processing sketch files into java, and then runs the java files + * through the JDT compiler. Errors returned are reflected back on the + * source files. + *
+ * Uses the PDE's sketch folder setup, with an additional /bin/ folder to save the
+ * build state and intermediate files.
+ *
+ * @author lonnen
+ *
+ */
+public class ProcessingSketchAuditor extends IncrementalProjectBuilder {
+
+ public static final String BUILDER_ID = ProcessingEditorPlugin.PLUGIN_ID + ".procesingSketchBuilder";
+
+ /**
+ * Adds the processing builder to a project
+ *
+ * @param project the project whose build spec we are to modify
+ */
+ public static void addBuilderToProject(IProject project){
+
+ //cannot modify closed projects
+ if (!project.isOpen())
+ return;
+
+ IProjectDescription description;
+ try{
+ description = project.getDescription();
+ } catch (Exception e){
+ ProcessingLog.logError(e);
+ return;
+ }
+
+ // Look for builders already associated with the project
+ ICommand[] cmds = description.getBuildSpec();
+ for (int j = 0; j < cmds.length; j++){
+ if (cmds[j].getBuilderName().equals(BUILDER_ID))
+ return;
+ }
+
+ //Associate builder with project.
+ ICommand newCmd = description.newCommand();
+ newCmd.setBuilderName(BUILDER_ID);
+ List
+ * Decides whether a full or incremental build is appropriate. Right now,
+ * the answer is always a full build. @see incrementalBuild
+ *
+ * @param kind the build type
+ * @param args build arguments
+ * @param monitor let the user know things are happening
+ */
+ protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {
+// if (kind == IncrementalProjectBuilder.FULL_BUILD){
+// fullBuild(monitor);
+// } else {
+// IResourceDelta delta = getDelta(getProject());
+// if (delta==null){
+// fullBuild(monitor);
+// } else {
+// incrementalBuild(delta, monitor);
+// }
+// }
+ System.out.println("BUILD!");
+
+ // every build is a full build for now, @see incrementalBuild
+ fullBuild(monitor);
+ return null;
+ }
+
+ /**
+ * re-compile only the files that have changed
+ *
+ * should be much faster than a full build, but because the preprocessor
+ * mashes together all the source files for a sketch, there is only one
+ * resource that gets changed every time a sketch is compiled. Until the
+ * preprocessor is rewritten and can mark up multiple files, every recompile
+ * request will result in a full build. To save a little time, the build
+ * method has been modified to reflect this and never call the incremental
+ * builder, so we avoid the hassle of crawling the resources to try and
+ * identify which ones will be recomputed -- its safe to assume all of the
+ * files will be used because even the ones that are unchanged will be
+ * grabbed eventually.
+ *
+ * @param delta an object containing the resource changes
+ * @param monitor let the user know things are happening
+ */
+ @SuppressWarnings("unused")
+ private void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) {
+ System.out.println("Incremental build on "+delta);
+ try{
+ delta.accept(new IResourceDeltaVisitor() {
+ public boolean visit(IResourceDelta delta){
+ System.out.println("changed: "+delta.getResource().getRawLocation());
+ return true; // true visits children of the resource
+ // this is important for folders
+ }
+ });
+ } catch (CoreException e) {
+ e.printStackTrace(); // perhaps we should pass this on
+ //perhaps we should do something with it instead
+ }
+ }
+
+ /**
+ * completely rebuilds the sketch file
+ *
+ * this code is essentially a translation of the processing.core sketch
+ * code to the Eclipse platform. The same code cannot just be reused
+ * because we need to use the Eclipse virtual file system to access files
+ * from inside Eclipse.
+ *
+ * @param monitor let the user know things are happening
+ * @throws CoreException if there are problems accessing the files
+ */
+ private void fullBuild(IProgressMonitor monitor) throws CoreException {
+
+ monitor.beginTask("Full Project Build", 4); // no idea how much 'work' to do here
+ IProject proj = getProject(); // get the project
+
+ if(checkCancel(monitor))
+ return;
+
+ if(!deleteProblemMarkers(proj))
+ return;
+
+ // IResource.members() doesn't return the files in a consistent order
+ // so we get the list at the beginning of each build and use folderContents
+ // whenever we need to get access to the source files during the build.
+ IResource[] folderContents = proj.members(); //TODO make this location a preference, link to sketchbook
+
+ // 1. concatenate all .pde files to the 'main' pde
+
+ StringBuffer bigCode = new StringBuffer(); // this will hold the program
+ int bigCount = 0; // how many lines are we talking about here?
+
+ // without a SketchCode object, this field needs to be tracked independently
+ int[] preprocOffsets = new int[folderContents.length];
+
+ for(int i = 0; i < folderContents.length; i++){
+ IResource file = folderContents[i];
+ if(file.getFileExtension() == "pde"){ // filters out only .pde files
+ String content = readFile((IFile) file);
+ preprocOffsets[i] = bigCount;
+ bigCode.append(content);
+ bigCode.append("\n");
+ bigCount += getLineCount(content);
+ }
+ }
+
+ monitor.worked(1);
+ if(checkCancel(monitor))
+ return;
+
+ spoof_preferences();// fake the preferences object.
+ PdePreprocessor preproc = new PdePreprocessor(proj.getName(), 4); //TODO make tab size a preference?
+
+ //final File java = new File(buildPath, name + ".java");
+ IFolder outputFolder = proj.getFolder("bin"); // just a handle to the resource //TODO make the derived resources folder a preference
+ if (!outputFolder.exists())
+ outputFolder.create(IResource.NONE, true, null);
+
+ PreprocessResult result = null;
+ try{
+ IFile outputFile = outputFolder.getFile(proj.getName() + ".java");
+
+ StringWriter outputFileContents = new StringWriter();
+ result = preproc.write(outputFileContents, bigCode.toString());
+
+ // Ugh. It wants an InputStream
+ ByteArrayInputStream inStream = new ByteArrayInputStream(outputFileContents.toString().getBytes());
+
+ outputFile.create(inStream, true, monitor); // force flag = true means this should overwrite any existing files
+ outputFile.setDerived(true); // let the platform know this is a generated file
+
+ }catch(antlr.RecognitionException re){
+ //TODO define the RecognitionException problem marker
+
+ // first assume that it's the main file
+ int errorFile = 0;
+ int errorLine = re.getLine() - 1;
+
+ // then search through for anyone else whose preprocName is null,
+ // since they've also been combined into the main pde
+ for(int i = 1; i < folderContents.length; i++){
+ IResource file = folderContents[i];
+ if(file.getFileExtension() == "pde" && (preprocOffsets[i] < errorLine)){
+ errorFile = i;
+ }
+ }
+ errorLine -= preprocOffsets[errorFile];
+
+ //DEBUG
+ System.out.println("error line - error file - offset");
+ System.out.println(errorLine + " - " + errorFile + " - " + preprocOffsets[errorFile]);
+
+ String msg = re.getMessage();
+
+ if (msg.equals("expecting RCURLY, found 'null'")) {
+ // This can be a problem since the error is sometimes listed as a line
+ // that's actually past the number of lines. For instance, it might
+ // report "line 15" of a 14 line program. Added code to highlightLine()
+ // inside Editor to deal with this situation (since that code is also
+ // useful for other similar situations).
+ msg = "Found one too many { characters without a } to match it.";
+ }
+ if (msg.indexOf("expecting RBRACK") != -1) {
+ msg = "Syntax error, maybe a missing right ] character?";
+ }
+ if (msg.indexOf("expecting SEMI") != -1) {
+ msg = "Syntax error, maybe a missing semicolon?";
+ }
+ if (msg.indexOf("expecting RPAREN") != -1) {
+ msg = "Syntax error, maybe a missing right parenthesis?";
+ }
+ if (msg.indexOf("preproc.web_colors") != -1) {
+ msg = "A web color (such as #ffcc00) must be six digits.";
+ }
+
+ // if there is no friendly translation, just report what you can
+ reportProblem(msg, (IFile) folderContents[errorFile], errorLine, true);
+
+ } catch (Exception e){
+ ProcessingLog.logError(e);
+ }
+
+ monitor.worked(1);
+ if(checkCancel(monitor))
+ return;
+
+ // copy any .java files to the output directory
+ for(int i = 0; i < folderContents.length; i++){
+ IResource file = folderContents[i];
+ if(file.getFileExtension() == "java"){ // copy .java files into the build directory
+ folderContents[i].copy(outputFolder.getProjectRelativePath(), IResource.DERIVED, monitor);
+ } else if (file.getFileExtension() == "pde"){
+ // The compiler and runner will need this to have a proper offset
+ preprocOffsets[i] += result.headerOffset;
+ }
+ }
+
+ boolean foundMain = preproc.getFoundMain(); // is this still necessary?
+
+
+ monitor.worked(1);
+ if(checkCancel(monitor))
+ return;
+
+ //to the java batch compiler!
+ //org.eclipse.jdt.core.compiler.CompilationProgress progress = null;
+
+// String baseCommand[] = new String[]{
+// "-Xemacs",
+// //"-noExit", // not necessary for ecj
+// "-source", "1.5",
+// "-target", "1.5",
+// "-classpath", sketch.getClassPath(),
+// "-nowarn", // we're not currently interested in warnings (works in ecj)
+// "-d", buildPath // output the classes in the buildPath
+// };
+
+ //org.eclipse.jdt.core.compiler.batch.BatchCompiler.compile("-verbose", new PrintWriter(System.out), new PrintWriter(System.err), progress);
+ // do something with it
+
+ // finally, let the monitor know things are done
+ monitor.done();
+ }
+
+ /**
+ * Try to delete all of the existing problem markers
+ *
+ * This should also catch all markers that inherit from IMarker.PROBLEM,
+ * which includes all of the special marker types for Processing. *
+ *
+ * @param project the project to be stripped of problem markers
+ * @return true if all markers were deleted, false if some remain
+ */
+ protected static boolean deleteProblemMarkers(IProject project) {
+ //TODO change this to remove markers specific to the Processing builder only
+ // though that requires making Processing specific markers first
+ try{
+ project.deleteMarkers(IMarker.PROBLEM, false, IResource.DEPTH_INFINITE);
+ return true;
+ } catch (CoreException e) {
+ ProcessingLog.logError(e);
+ return false;
+ }
+ }
+
+ /**
+ * utility method to read in a file and return it as a string
+ *
+ * @param file a resource handler for a file
+ * @return contents of the file
+ */
+ private String readFile(IFile file) {
+ if (!file.exists())
+ return "";
+ InputStream stream = null;
+ try{
+ stream = file.getContents();
+ Reader reader = new BufferedReader(new InputStreamReader(stream));
+ StringBuffer result = new StringBuffer(2048);
+ char[] buf = new char[2048];
+ while (true){
+ int count = reader.read(buf);
+ if (count < 0)
+ break;
+ result.append(buf, 0, count);
+ }
+ return result.toString();
+ } catch (Exception e){ // IOException and CoreException
+ ProcessingLog.logError(e);
+ return "";
+ } finally {
+ try{
+ if (stream != null)
+ stream.close();
+ } catch (IOException e){
+ ProcessingLog.logError(e);
+ return "";
+ }
+ }
+ }
+
+ private int getLineCount(String what){
+ int count = 1;
+ for (char c : what.toCharArray()) {
+ if (c == '\n') count++;
+ }
+ return count;
+ }
+
+ /**
+ * Generates a problem marker from the preprocessor output
+ *
+ * The preprocessor only hands back a line and column. This method reports the whole
+ * line and the message like the PDE.
+ *
+ * @param msg error message
+ * @param file where the problem occurred
+ * @param line_number what line did the problem occur on
+ * @param isError is this an error
+ */
+ private void reportProblem( String msg, IFile file, int line_number, boolean isError){
+ System.out.println( (isError ? "ERROR: " : "WARNING: ") + msg);
+ try{
+ IMarker marker = file.createMarker(IMarker.PROBLEM);
+ marker.setAttribute(IMarker.MESSAGE, msg);
+ marker.setAttribute(IMarker.LINE_NUMBER, line_number);
+ marker.setAttribute(IMarker.SEVERITY, isError ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING);
+ } catch(CoreException e){
+ ProcessingLog.logError(e);
+ return;
+ }
+
+ }
+
+ /**
+ * Checks the progress monitor for interruption
+ *
+ * @param monitor
+ * @return true if the monitor is interrupted, false otherwise
+ */
+ private boolean checkCancel(IProgressMonitor monitor){
+ if (monitor.isCanceled()){
+ throw new OperationCanceledException();
+ }
+ if (isInterrupted()){
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sets up the Static processing.app.Preferences class.
+ */
+ private void spoof_preferences(){
+ Preferences.set("editor.tabs.size", "4");
+ Preferences.set("preproc.substitute_floats","true");
+ Preferences.set("preproc.web_colors", "true");
+ Preferences.set("preproc.color_datatype", "true");
+ Preferences.set("preproc.enhanced_casting", "true");
+ Preferences.set("preproc.substitute.unicode", "true");
+ Preferences.set("preproc.output_parse.tree", "false");
+ Preferences.set("export.application.fullscreen", "false");
+ Preferences.set("run.present.bgcolor", "#666666");
+ Preferences.set("export.application.stop", "true");
+ Preferences.set("run.present.stop.color", "#cccccc");
+ Preferences.set("run.window.bgcolor", "#ECE9D8");
+ Preferences.set("preproc.imports.list", "java.applet.*,java.awt.Dimension,java.awt.Frame,java.awt.event.MouseEvent,java.awt.event.KeyEvent,java.awt.event.FocusEvent,java.awt.Image,java.io.*,java.net.*,java.text.*,java.util.*,java.util.zip.*,java.util.regex.*");
+ }
+
+}
diff --git a/editor/org.processing.editor/src/org/processing/builder/ProcessingSketchNature.java b/editor/org.processing.editor/src/org/processing/builder/ProcessingSketchNature.java
new file mode 100644
index 000000000..d34b29aa2
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/builder/ProcessingSketchNature.java
@@ -0,0 +1,60 @@
+package org.processing.builder;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectNature;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.processing.editor.ProcessingLog;
+
+public class ProcessingSketchNature implements IProjectNature {
+
+ private IProject project;
+
+ /**
+ * Access method for this natures project
+ */
+ public IProject getProject() {
+ return project;
+ }
+
+ /**
+ * Sets the project this nature is managing
+ */
+ public void setProject(IProject project) {
+ this.project = project;
+ }
+
+ /**
+ * associate the processing sketch builder with the project
+ */
+ public void configure() throws CoreException {
+ ProcessingSketchAuditor.addBuilderToProject(project);
+ new Job("Processing Sketch Audit"){
+ protected IStatus run(IProgressMonitor monitor){
+ try{
+ project.build(
+ ProcessingSketchAuditor.FULL_BUILD,
+ ProcessingSketchAuditor.BUILDER_ID,
+ null,
+ monitor);
+ } catch (CoreException e){
+ ProcessingLog.logError(e);
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ /**
+ * dissociate the processing sketch builder from the project
+ * and remove the markers it generated.
+ */
+ public void deconfigure() throws CoreException {
+ ProcessingSketchAuditor.removeBuilderFromProject(project);
+ ProcessingSketchAuditor.deleteProblemMarkers(project);
+ }
+
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/PresentationAction.java b/editor/org.processing.editor/src/org/processing/editor/PresentationAction.java
new file mode 100644
index 000000000..f5785a5dc
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/PresentationAction.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor;
+
+
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.texteditor.TextEditorAction;
+
+/**
+ * A toolbar action which toggles the presentation model of the
+ * connected text editor. The editor shows either the highlight range
+ * only or always the whole document.
+ */
+public class PresentationAction extends TextEditorAction {
+
+ /**
+ * Constructs and updates the action.
+ */
+ public PresentationAction() {
+ super(ProcessingEditorMessages.getResourceBundle(), "TogglePresentation.", null); //$NON-NLS-1$
+ update();
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IAction
+ */
+ public void run() {
+
+ ITextEditor editor= getTextEditor();
+
+ editor.resetHighlightRange();
+ boolean show= editor.showsHighlightRangeOnly();
+ setChecked(!show);
+ editor.showHighlightRangeOnly(!show);
+ }
+
+ /* (non-Javadoc)
+ * Method declared on TextEditorAction
+ */
+ public void update() {
+ setChecked(getTextEditor() != null && getTextEditor().showsHighlightRangeOnly());
+ setEnabled(true);
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/ProcessingActionContributor.java b/editor/org.processing.editor/src/org/processing/editor/ProcessingActionContributor.java
new file mode 100644
index 000000000..0e9c8f807
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/ProcessingActionContributor.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor;
+
+
+import org.eclipse.jface.action.*;
+import org.eclipse.ui.*;
+import org.eclipse.ui.editors.text.TextEditorActionContributor;
+import org.eclipse.ui.texteditor.*;
+
+/**
+ * Contributes interesting Java actions to the desktop's Edit menu and the toolbar.
+ */
+public class ProcessingActionContributor extends TextEditorActionContributor {
+
+ protected RetargetTextEditorAction fContentAssistProposal;
+ protected RetargetTextEditorAction fContentAssistTip;
+ protected TextEditorAction fTogglePresentation;
+
+ /**
+ * Default constructor.
+ */
+ public ProcessingActionContributor() {
+ super();
+ fContentAssistProposal= new RetargetTextEditorAction(ProcessingEditorMessages.getResourceBundle(), "ContentAssistProposal."); //$NON-NLS-1$
+ fContentAssistProposal.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
+ fContentAssistTip= new RetargetTextEditorAction(ProcessingEditorMessages.getResourceBundle(), "ContentAssistTip."); //$NON-NLS-1$
+ fContentAssistTip.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_CONTEXT_INFORMATION);
+ fTogglePresentation= new PresentationAction();
+ }
+
+ /*
+ * @see IEditorActionBarContributor#init(IActionBars)
+ */
+ public void init(IActionBars bars) {
+ super.init(bars);
+
+ IMenuManager menuManager= bars.getMenuManager();
+ IMenuManager editMenu= menuManager.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT);
+ if (editMenu != null) {
+ editMenu.add(new Separator());
+ editMenu.add(fContentAssistProposal);
+ editMenu.add(fContentAssistTip);
+ }
+
+ IToolBarManager toolBarManager= bars.getToolBarManager();
+ if (toolBarManager != null) {
+ toolBarManager.add(new Separator());
+ toolBarManager.add(fTogglePresentation);
+ }
+ }
+
+ /*
+ *
+ */
+ private void doSetActiveEditor(IEditorPart part) {
+ super.setActiveEditor(part);
+
+ ITextEditor editor= null;
+ if (part instanceof ITextEditor)
+ editor= (ITextEditor) part;
+
+ fContentAssistProposal.setAction(getAction(editor, "ContentAssistProposal")); //$NON-NLS-1$
+ fContentAssistTip.setAction(getAction(editor, "ContentAssistTip")); //$NON-NLS-1$
+
+ fTogglePresentation.setEditor(editor);
+ fTogglePresentation.update();
+ }
+
+ /*
+ * @see IEditorActionBarContributor#setActiveEditor(IEditorPart)
+ */
+ public void setActiveEditor(IEditorPart part) {
+ super.setActiveEditor(part);
+ doSetActiveEditor(part);
+ }
+
+ /*
+ * @see IEditorActionBarContributor#dispose()
+ */
+ public void dispose() {
+ doSetActiveEditor(null);
+ super.dispose();
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/ProcessingAnnotationHover.java b/editor/org.processing.editor/src/org/processing/editor/ProcessingAnnotationHover.java
new file mode 100644
index 000000000..33f9d14e3
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/ProcessingAnnotationHover.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor;
+
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.source.IAnnotationHover;
+import org.eclipse.jface.text.source.ISourceViewer;
+
+/**
+ * Provides the information thats displayed in the presentation area of hover popup windows.
+ * Right now this doesn't provide anything useful. It just hands back the contents of the line
+ * the mouse is hovering on.
+ *
+ * @see org.eclipse.jface.text.source.IAnnotationHover
+ */
+
+public class ProcessingAnnotationHover implements IAnnotationHover {
+
+ /* (non-Javadoc)
+ * Method declared on IAnnotationHover
+ */
+ public String getHoverInfo(ISourceViewer sourceViewer, int lineNumber) {
+ IDocument document= sourceViewer.getDocument();
+
+ try {
+ IRegion info= document.getLineInformation(lineNumber);
+ return document.get(info.getOffset(), info.getLength());
+ } catch (BadLocationException x) {
+ }
+
+ return null;
+ }
+
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/ProcessingContentOutlinePage.java b/editor/org.processing.editor/src/org/processing/editor/ProcessingContentOutlinePage.java
new file mode 100644
index 000000000..71900ee36
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/ProcessingContentOutlinePage.java
@@ -0,0 +1,253 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor;
+
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.BadPositionCategoryException;
+import org.eclipse.jface.text.DefaultPositionUpdater;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IPositionUpdater;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.texteditor.IDocumentProvider;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
+
+/**
+ * A content outline page which always represents the content of the
+ * connected editor in 10 segments.
+ */
+public class ProcessingContentOutlinePage extends ContentOutlinePage {
+
+ /**
+ * A segment element.
+ */
+ protected static class Segment {
+ public String name;
+ public Position position;
+
+ public Segment(String name, Position position) {
+ this.name= name;
+ this.position= position;
+ }
+
+ public String toString() {
+ return name;
+ }
+ }
+
+ /**
+ * Divides the editor's document into ten segments and provides elements for them.
+ */
+ protected class ContentProvider implements ITreeContentProvider {
+
+ protected final static String SEGMENTS= "__java_segments"; //$NON-NLS-1$
+ protected IPositionUpdater fPositionUpdater= new DefaultPositionUpdater(SEGMENTS);
+ protected List fContent= new ArrayList(10);
+
+ protected void parse(IDocument document) {
+
+ int lines= document.getNumberOfLines();
+ int increment= Math.max(Math.round(lines / 10), 10);
+
+ for (int line= 0; line < lines; line += increment) {
+
+ int length= increment;
+ if (line + increment > lines)
+ length= lines - line;
+
+ try {
+
+ int offset= document.getLineOffset(line);
+ int end= document.getLineOffset(line + length);
+ length= end - offset;
+ Position p= new Position(offset, length);
+ document.addPosition(SEGMENTS, p);
+ fContent.add(new Segment(MessageFormat.format(ProcessingEditorMessages.getString("OutlinePage.segment.title_pattern"), new Object[] { new Integer(offset) }), p)); //$NON-NLS-1$
+
+ } catch (BadPositionCategoryException x) {
+ } catch (BadLocationException x) {
+ }
+ }
+ }
+
+ /*
+ * @see IContentProvider#inputChanged(Viewer, Object, Object)
+ */
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ if (oldInput != null) {
+ IDocument document= fDocumentProvider.getDocument(oldInput);
+ if (document != null) {
+ try {
+ document.removePositionCategory(SEGMENTS);
+ } catch (BadPositionCategoryException x) {
+ }
+ document.removePositionUpdater(fPositionUpdater);
+ }
+ }
+
+ fContent.clear();
+
+ if (newInput != null) {
+ IDocument document= fDocumentProvider.getDocument(newInput);
+ if (document != null) {
+ document.addPositionCategory(SEGMENTS);
+ document.addPositionUpdater(fPositionUpdater);
+
+ parse(document);
+ }
+ }
+ }
+
+ /*
+ * @see IContentProvider#dispose
+ */
+ public void dispose() {
+ if (fContent != null) {
+ fContent.clear();
+ fContent= null;
+ }
+ }
+
+ /*
+ * @see IContentProvider#isDeleted(Object)
+ */
+ public boolean isDeleted(Object element) {
+ return false;
+ }
+
+ /*
+ * @see IStructuredContentProvider#getElements(Object)
+ */
+ public Object[] getElements(Object element) {
+ return fContent.toArray();
+ }
+
+ /*
+ * @see ITreeContentProvider#hasChildren(Object)
+ */
+ public boolean hasChildren(Object element) {
+ return element == fInput;
+ }
+
+ /*
+ * @see ITreeContentProvider#getParent(Object)
+ */
+ public Object getParent(Object element) {
+ if (element instanceof Segment)
+ return fInput;
+ return null;
+ }
+
+ /*
+ * @see ITreeContentProvider#getChildren(Object)
+ */
+ public Object[] getChildren(Object element) {
+ if (element == fInput)
+ return fContent.toArray();
+ return new Object[0];
+ }
+ }
+
+ protected Object fInput;
+ protected IDocumentProvider fDocumentProvider;
+ protected ITextEditor fTextEditor;
+
+ /**
+ * Creates a content outline page using the given provider and the given editor.
+ *
+ * @param provider the document provider
+ * @param editor the editor
+ */
+ public ProcessingContentOutlinePage(IDocumentProvider provider, ITextEditor editor) {
+ super();
+ fDocumentProvider= provider;
+ fTextEditor= editor;
+ }
+
+ /* (non-Javadoc)
+ * Method declared on ContentOutlinePage
+ */
+ public void createControl(Composite parent) {
+
+ super.createControl(parent);
+
+ TreeViewer viewer= getTreeViewer();
+ viewer.setContentProvider(new ContentProvider());
+ viewer.setLabelProvider(new LabelProvider());
+ viewer.addSelectionChangedListener(this);
+
+ if (fInput != null)
+ viewer.setInput(fInput);
+ }
+
+ /* (non-Javadoc)
+ * Method declared on ContentOutlinePage
+ */
+ public void selectionChanged(SelectionChangedEvent event) {
+
+ super.selectionChanged(event);
+
+ ISelection selection= event.getSelection();
+ if (selection.isEmpty())
+ fTextEditor.resetHighlightRange();
+ else {
+ Segment segment= (Segment) ((IStructuredSelection) selection).getFirstElement();
+ int start= segment.position.getOffset();
+ int length= segment.position.getLength();
+ try {
+ fTextEditor.setHighlightRange(start, length, true);
+ } catch (IllegalArgumentException x) {
+ fTextEditor.resetHighlightRange();
+ }
+ }
+ }
+
+ /**
+ * Sets the input of the outline page
+ *
+ * @param input the input of this outline page
+ */
+ public void setInput(Object input) {
+ fInput= input;
+ update();
+ }
+
+ /**
+ * Updates the outline page.
+ */
+ public void update() {
+ TreeViewer viewer= getTreeViewer();
+
+ if (viewer != null) {
+ Control control= viewer.getControl();
+ if (control != null && !control.isDisposed()) {
+ control.setRedraw(false);
+ viewer.setInput(fInput);
+ viewer.expandAll();
+ control.setRedraw(true);
+ }
+ }
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/ProcessingDocumentSetupParticipant.java b/editor/org.processing.editor/src/org/processing/editor/ProcessingDocumentSetupParticipant.java
new file mode 100644
index 000000000..bad95c6af
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/ProcessingDocumentSetupParticipant.java
@@ -0,0 +1,35 @@
+package org.processing.editor;
+
+import org.eclipse.core.filebuffers.IDocumentSetupParticipant;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentExtension3;
+import org.eclipse.jface.text.IDocumentPartitioner;
+import org.eclipse.jface.text.rules.FastPartitioner;
+
+/**
+ * Participates in the setup of a text file buffer document.
+ *
+ * Requires the "org.eclipse.core.filebuffers.documentSetup" extension point.
+ *
+ * @see org.eclipse.core.filebuffers.IDocumentSetupParticipant
+ */
+public class ProcessingDocumentSetupParticipant implements IDocumentSetupParticipant {
+
+ /**
+ * Doesn't do much.
+ */
+ public ProcessingDocumentSetupParticipant() {
+ }
+
+ /**
+ * Sets up the document.
+ */
+ public void setup(IDocument document) {
+ if (document instanceof IDocumentExtension3) {
+ IDocumentExtension3 extension3= (IDocumentExtension3) document;
+ IDocumentPartitioner partitioner= new FastPartitioner(ProcessingEditorPlugin.getDefault().getProcessingPartitionScanner(), ProcessingPartitionScanner.JAVA_PARTITION_TYPES);
+ extension3.setDocumentPartitioner(ProcessingEditorPlugin.PROCESSING_PARTITIONING, partitioner);
+ partitioner.connect(document);
+ }
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/ProcessingEditor.java b/editor/org.processing.editor/src/org/processing/editor/ProcessingEditor.java
new file mode 100644
index 000000000..d6c871906
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/ProcessingEditor.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor;
+
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.text.ITextViewerExtension5;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.IVerticalRuler;
+import org.eclipse.jface.text.source.projection.ProjectionSupport;
+import org.eclipse.jface.text.source.projection.ProjectionViewer;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.editors.text.TextEditor;
+import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
+import org.eclipse.ui.texteditor.TextOperationAction;
+
+/**
+ * Sets up a Processing specific text editor.
+ *
+ * @see org.eclipse.ui.editors.text.TextEditor
+ */
+public class ProcessingEditor extends TextEditor {
+
+ /** The outline page */
+ private ProcessingContentOutlinePage fOutlinePage;
+ /** The projection support */
+ private ProjectionSupport fProjectionSupport;
+
+ /**
+ * Default
+ */
+ public ProcessingEditor() {
+ super();
+ }
+
+ /** The
+ * Two editor preferences are included as examples, but
+ * currently do not do anything.
+ *
+ * //TODO transfer Processing.app preferences here
+ * this may involve subclassing PreferencePage,
+ * but things could be setup such that these are read
+ * from a file, and we could use a customized version of
+ * a standard Processing preferences file to store this.
+ *
+ * Added some validation and warning messages as examples.
+ * If we really want to implement ones of any complexity
+ * there should be an addition of propertyChange() and checkState()
+ * methods.
+ * See: http://sites.google.com/site/eclipseplugindevelopment/9-preference-pages
+ */
+
+public class ProcessingPreferencesPage
+ extends FieldEditorPreferencePage
+ implements IWorkbenchPreferencePage {
+
+ public ProcessingPreferencesPage() {
+ super(GRID);
+ setPreferenceStore(ProcessingEditorPlugin.getDefault().getPreferenceStore());
+ setDescription("Processing Plugin Preferences (nothing here is used, see JavaDoc)");
+ }
+
+ /**
+ * Creates the field editors. Field editors are abstractions of
+ * the common GUI blocks needed to manipulate various types
+ * of preferences. Each field editor knows how to save and
+ * restore itself.
+ */
+ public void createFieldEditors() {
+ // Sketchbook Directory Item setup
+ DirectoryFieldEditor nextField = new DirectoryFieldEditor(PreferenceConstants.PROCESSING_SKETCHBOOK, "Sketchbook Directory:", getFieldEditorParent());
+ nextField.setEmptyStringAllowed(false);
+ nextField.setErrorMessage("The Sketchbook Directory shouldn't be empty!");
+ addField(nextField);
+ // Library Path item setup
+ nextField = new DirectoryFieldEditor(PreferenceConstants.PROCESSING_LIBRARIES, "Processing Library Path:", getFieldEditorParent());
+ nextField.setEmptyStringAllowed(false);
+ nextField.setErrorMessage("A library path is required to use libraries!");
+ addField(nextField);
+ // Checkbox example setup!
+ addField(
+ new BooleanFieldEditor(
+ PreferenceConstants.PROCESSING_AUTO_INDENT,
+ "Auto indent",
+ getFieldEditorParent()));
+ }
+
+ /**
+ * Initializes the preference page. Nothing to do here, but it has to be subclassed.
+ */
+ public void init(IWorkbench workbench) {}
+
+}
\ No newline at end of file
ProcessingEditor implementation of this
+ * AbstractTextEditor method extend the
+ * actions to add those specific to the receiver
+ */
+ protected void createActions() {
+ super.createActions();
+
+ IAction a= new TextOperationAction(ProcessingEditorMessages.getResourceBundle(), "ContentAssistProposal.", this, ISourceViewer.CONTENTASSIST_PROPOSALS); //$NON-NLS-1$
+ a.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
+ setAction("ContentAssistProposal", a); //$NON-NLS-1$
+
+ a= new TextOperationAction(ProcessingEditorMessages.getResourceBundle(), "ContentAssistTip.", this, ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION); //$NON-NLS-1$
+ a.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_CONTEXT_INFORMATION);
+ setAction("ContentAssistTip", a); //$NON-NLS-1$
+ }
+
+ /** The ProcessingEditor implementation of this
+ * AbstractTextEditor method performs any extra
+ * disposal actions required by the java editor.
+ */
+ public void dispose() {
+ if (fOutlinePage != null)
+ fOutlinePage.setInput(null);
+ super.dispose();
+ }
+
+ /** The ProcessingEditor implementation of this
+ * AbstractTextEditor method performs any extra
+ * revert behavior required by the java editor.
+ */
+ public void doRevertToSaved() {
+ super.doRevertToSaved();
+ if (fOutlinePage != null)
+ fOutlinePage.update();
+ }
+
+ /** The ProcessingEditor implementation of this
+ * AbstractTextEditor method performs any extra
+ * save behavior required by the java editor.
+ *
+ * @param monitor the progress monitor
+ */
+ public void doSave(IProgressMonitor monitor) {
+ super.doSave(monitor);
+ if (fOutlinePage != null)
+ fOutlinePage.update();
+ }
+
+ /** The ProcessingEditor implementation of this
+ * AbstractTextEditor method performs any extra
+ * save as behavior required by the java editor.
+ */
+ public void doSaveAs() {
+ super.doSaveAs();
+ if (fOutlinePage != null)
+ fOutlinePage.update();
+ }
+
+ /** The ProcessingEditor implementation of this
+ * AbstractTextEditor method performs sets the
+ * input of the outline page after AbstractTextEditor has set input.
+ *
+ * @param input the editor input
+ * @throws CoreException in case the input can not be set
+ */
+ public void doSetInput(IEditorInput input) throws CoreException {
+ super.doSetInput(input);
+ if (fOutlinePage != null)
+ fOutlinePage.setInput(input);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void editorContextMenuAboutToShow(IMenuManager menu) {
+ super.editorContextMenuAboutToShow(menu);
+ //These menu items are linked to non-functional things. Disabling [lonnen] june 18, 2010
+ //addAction(menu, "ContentAssistProposal"); //$NON-NLS-1$
+ //addAction(menu, "ContentAssistTip"); //$NON-NLS-1$
+ }
+
+//TODO Write a useful outline
+// The outline wasn't doing anything useful. Until it does, leave this commented
+// out to keep the outline from showing up at all.
+//
+// /** The ProcessingEditor implementation of this
+// * AbstractTextEditor method gets the outline page
+// * when it is requested.
+// *
+// * @param required the required type
+// * @return an adapter for the required type or null
+// */
+// public Object getAdapter(Class required) {
+//
+// if (IContentOutlinePage.class.equals(required)) {
+// if (fOutlinePage == null) {
+// fOutlinePage= new ProcessingContentOutlinePage(getDocumentProvider(), this);
+// if (getEditorInput() != null)
+// fOutlinePage.setInput(getEditorInput());
+// }
+// return fOutlinePage;
+// }
+//
+// if (fProjectionSupport != null) {
+// Object adapter= fProjectionSupport.getAdapter(getSourceViewer(), required);
+// if (adapter != null)
+// return adapter;
+// }
+//
+// return super.getAdapter(required);
+// }
+
+ /**
+ * Initializes this editor and provides a SourceViewerConfiguration
+ *
+ * @see org.eclipse.jface.text.source.SourceViewerConfiguration
+ */
+ protected void initializeEditor() {
+ super.initializeEditor();
+ setSourceViewerConfiguration(new ProcessingSourceViewerConfiguration());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
+
+ fAnnotationAccess= createAnnotationAccess();
+ fOverviewRuler= createOverviewRuler(getSharedColors());
+
+ ISourceViewer viewer= new ProjectionViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(), styles);
+
+ // ensure decoration support has been created and configured.
+ // preferred over SourceViewerDecorationSupport due to impending API changes [lonnen] june 11, 2010
+ fSourceViewerDecorationSupport = getSourceViewerDecorationSupport(viewer);
+
+ return viewer;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.texteditor.ExtendedTextEditor#createPartControl(org.eclipse.swt.widgets.Composite)
+ */
+ public void createPartControl(Composite parent) {
+ super.createPartControl(parent);
+ ProjectionViewer viewer= (ProjectionViewer) getSourceViewer();
+ fProjectionSupport= new ProjectionSupport(viewer, getAnnotationAccess(), getSharedColors());
+ fProjectionSupport.addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.error"); //$NON-NLS-1$
+ fProjectionSupport.addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.warning"); //$NON-NLS-1$
+ fProjectionSupport.install();
+ viewer.doOperation(ProjectionViewer.TOGGLE);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.texteditor.AbstractTextEditor#adjustHighlightRange(int, int)
+ */
+ protected void adjustHighlightRange(int offset, int length) {
+ ISourceViewer viewer= getSourceViewer();
+ if (viewer instanceof ITextViewerExtension5) {
+ ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
+ extension.exposeModelRange(new Region(offset, length));
+ }
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/ProcessingEditorMessages.java b/editor/org.processing.editor/src/org/processing/editor/ProcessingEditorMessages.java
new file mode 100644
index 000000000..a2ff97029
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/ProcessingEditorMessages.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * Processing Editor Messages object handles localization stuff
+ * using the ProcessingEditorMessages.preferences file. This class
+ * is never instantiated, and all of its variables and methods are
+ * static.
+ *
+ * @author lonnen
+ */
+public class ProcessingEditorMessages {
+
+ private static final String RESOURCE_BUNDLE= "org.processing.editor.ProcessingEditorMessages";//$NON-NLS-1$
+
+ private static ResourceBundle fgResourceBundle= ResourceBundle.getBundle(RESOURCE_BUNDLE);
+
+ private ProcessingEditorMessages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return fgResourceBundle.getString(key);
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+
+ public static ResourceBundle getResourceBundle() {
+ return fgResourceBundle;
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/ProcessingEditorMessages.properties b/editor/org.processing.editor/src/org/processing/editor/ProcessingEditorMessages.properties
new file mode 100644
index 000000000..840497670
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/ProcessingEditorMessages.properties
@@ -0,0 +1,46 @@
+###############################################################################
+# Copyright (c) 2000, 2005 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+
+# Essentially the same as JavaEditorMessage.properties from the Java example [lonnen] June 10 2010
+
+## Actions ##
+
+ContentAssistProposal.label=Content Assist@Ctrl+SPACE
+ContentAssistProposal.tooltip=Content Assist
+ContentAssistProposal.image=
+ContentAssistProposal.description=Content Assist
+
+ContentAssistTip.label=Content Tip@Ctrl+SHIFT+SPACE
+ContentAssistTip.tooltip=Content Tip
+ContentAssistTip.image=
+ContentAssistTip.description=Content Tip
+
+DefineFoldingRegion.label=Define Folding Region
+DefineFoldingRegion.tooltip=Define Folding Region
+DefineFoldingRegion.image=
+DefineFoldingRegion.description=Define Folding Region
+
+TogglePresentation.label=Change Presentation
+TogglePresentation.tooltip=Enable/Disable Segmented Source Viewer
+TogglePresentation.image=togglepresentation.gif
+TogglePresentation.description=Enable/Disable Segmented Source Viewer
+
+OutlinePage.segment.title_pattern=position {0}
+
+AutoIndent.error.bad_location_1=JavaAutoIndentStrategy.getAutoIndentString: BadLocationException
+AutoIndent.error.bad_location_2=JavaAutoIndentStrategy.calcShiftBackReplace: BadLocationException
+
+CompletionProcessor.ContextInfo.display.pattern=proposal {0} at position {1}
+CompletionProcessor.ContextInfo.value.pattern=proposal {0} valid from {1} to {2}
+CompletionProcessor.Proposal.ContextInfo.pattern={0} valid 5 characters around insertion point
+CompletionProcessor.Proposal.hoverinfo.pattern=Java keyword: {0}
+
+JavaTextHover.emptySelection=empty selection
diff --git a/editor/org.processing.editor/src/org/processing/editor/ProcessingEditorPlugin.java b/editor/org.processing.editor/src/org/processing/editor/ProcessingEditorPlugin.java
new file mode 100644
index 000000000..45fa8dc55
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/ProcessingEditorPlugin.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.net.URL;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.jface.text.rules.RuleBasedScanner;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.processing.editor.javadoc.JavaDocScanner;
+import org.processing.editor.language.ProcessingCodeScanner;
+import org.processing.editor.util.ProcessingColorProvider;
+
+/**
+ * Processing editor plug-in class.
+ * Uses a singleton pattern to controls access to a few objects that need to be shared
+ * across the plugin. Access these options with ProcessingEditorPlugin.getDefault().method()
+ * @since 3.0
+ */
+public class ProcessingEditorPlugin extends AbstractUIPlugin {
+
+ public static final String PLUGIN_ID = "org.processing.ProcessingEditor";
+ //public static final String JAVA_PARTITIONING= "__java_example_partitioning"; //$NON-NLS-1$
+ public static final String PROCESSING_PARTITIONING= "__processing_partitioning"; //$NON-NLS-1$
+
+ // The shared instance
+ private static ProcessingEditorPlugin fgInstance;
+
+ // Supporting objects that are managed by the singleton
+ private ProcessingPartitionScanner fPartitionScanner;
+ private ProcessingColorProvider fColorProvider;
+ private ProcessingCodeScanner fCodeScanner;
+ private JavaDocScanner fDocScanner;
+
+ /**
+ * Creates a new plug-in instance.
+ */
+ public ProcessingEditorPlugin() {
+ //any init code should go in start()
+ }
+
+ /**
+ * Called when the plugin is loaded.
+ *
+ * All initialization stuff goes here. Make sure to de-initialize it in stop()
+ * Also, try to keep these methods lean. If it takes too long the platform will
+ * cancel loading the plug-in.
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ fgInstance = this;
+ }
+
+ /**
+ * Called when the plugin is unloaded.
+ *
+ * Make sure to remove anything here that was initialized to prevent memory
+ * leaks. Keep this lean, or the platform will cancel the operation.
+ */
+ public void stop(BundleContext context) throws Exception {
+ fgInstance = null;
+ super.stop(context);
+ }
+
+
+ /**
+ * Returns the default plug-in instance.
+ *
+ * @return the default plug-in instance
+ */
+ public static ProcessingEditorPlugin getDefault() { return fgInstance; }
+
+ /**
+ * Return a scanner for creating Processing partitions.
+ * Processing uses Java's commenting scheme, so our partitioner is almost identical. Unlike
+ * the Java partitioner, however, this Processing one currently treats the JavaDoc style
+ * comments as simple multiline comments.
+ *
+ * @return a scanner for creating Processing partitions
+ */
+ public ProcessingPartitionScanner getProcessingPartitionScanner() {
+ if (fPartitionScanner == null)
+ fPartitionScanner= new ProcessingPartitionScanner();
+ return fPartitionScanner;
+ }
+
+ /**
+ * Returns the singleton Processing code scanner.
+ *
+ * @return the singleton Processing code scanner
+ */
+ public RuleBasedScanner getProcessingCodeScanner() {
+ if (fCodeScanner == null)
+ fCodeScanner= new ProcessingCodeScanner(getProcessingColorProvider());
+ return fCodeScanner;
+ }
+
+ /**
+ * Returns the singleton Processing color provider.
+ *
+ * @return the singleton Processing color provider
+ */
+ public ProcessingColorProvider getProcessingColorProvider() {
+ if (fColorProvider == null)
+ fColorProvider= new ProcessingColorProvider();
+ return fColorProvider;
+ }
+
+ /**
+ * Returns the singleton Processingdoc scanner.
+ *
+ * @return the singleton Processingdoc scanner
+ */
+ public RuleBasedScanner getProcessingDocScanner() {
+ if (fDocScanner == null)
+ fDocScanner= new JavaDocScanner(fColorProvider);
+ return fDocScanner;
+ }
+
+ /**
+ * Returns a buffered input stream for a file in the plug-in directory.
+ *
+ * @param filename the file to be loaded
+ * @return BufferedInputStream to read the file with
+ */
+ public BufferedInputStream getFileInputStream(String filename) {
+ Bundle bundle = getDefault().getBundle();
+ URL fileLocation;
+ try {
+ fileLocation = FileLocator.toFileURL(bundle.getEntry(filename));
+ BufferedInputStream file = new BufferedInputStream(fileLocation.openStream());
+ return file;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null; // this should be more explicit than a null pointer from a caught exception, right? [lonnen] June 15, 2010
+ }
+
+
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/ProcessingLog.java b/editor/org.processing.editor/src/org/processing/editor/ProcessingLog.java
new file mode 100644
index 000000000..315ed625a
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/ProcessingLog.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+// This is actually all original code, but it is part of an EPL project, so maybe I still need this?
+// If I wanted to worry about licensing I would have applied to law school. Back to code. [lonnen] June 18 2010
+package org.processing.editor;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Container class for all the methods related to logging exceptions and other such
+ * information that is useful to have written to a log file somewhere.
+ *
+ * @author lonnen
+ */
+public class ProcessingLog {
+
+ // Who needs a constructor?
+
+ /**
+ * Convenience method for appending a string to the log file.
+ * Don't use this if there is an error.
+ *
+ * @param message something to append to the log file
+ */
+ public static void logInfo(String message){
+ log(IStatus.INFO, IStatus.OK, message, null);
+ }
+
+ /**
+ * Convenience method for appending an unexpected exception to the log file
+ *
+ * @param exception some problem
+ */
+ public static void logError(Throwable exception){
+ logError("Unexpected Exception", exception);
+ }
+
+ /**
+ * Convenience method for appending an exception with a message
+ *
+ * @param message a message, preferably something about the problem
+ * @param exception the problem
+ */
+ public static void logError(String message, Throwable exception){
+ log(IStatus.ERROR, IStatus.OK, message, exception);
+ }
+
+ /**
+ * Adapter method that creates the appropriate status to be logged
+ *
+ * @param severity integer code indicating the type of message
+ * @param code plug-in-specific status code
+ * @param message a human readable message
+ */
+ public static void log(int severity, int code, String message, Throwable exception){
+ log(createStatus(severity, code, message, exception));
+ }
+
+ /**
+ * Creates a status object to log
+ *
+ * @param severity integer code indicating the type of message
+ * @param code plug-in-specific status code
+ * @param message a human readable message
+ * @param a low-level exception, or null
+ * @return status object
+ */
+ public static IStatus createStatus(int severity, int code, String message, Throwable exception){
+ return new Status(severity, ProcessingEditorPlugin.PLUGIN_ID, code, message, exception);
+ }
+
+ /**
+ * Write a status to the log
+ *
+ * @param status
+ */
+ public static void log(IStatus status){
+ ProcessingEditorPlugin.getDefault().getLog().log(status);
+ }
+
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/ProcessingPartitionScanner.java b/editor/org.processing.editor/src/org/processing/editor/ProcessingPartitionScanner.java
new file mode 100644
index 000000000..27eea7283
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/ProcessingPartitionScanner.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.text.rules.EndOfLineRule;
+import org.eclipse.jface.text.rules.ICharacterScanner;
+import org.eclipse.jface.text.rules.IPredicateRule;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.IWordDetector;
+import org.eclipse.jface.text.rules.MultiLineRule;
+import org.eclipse.jface.text.rules.RuleBasedPartitionScanner;
+import org.eclipse.jface.text.rules.SingleLineRule;
+import org.eclipse.jface.text.rules.Token;
+import org.eclipse.jface.text.rules.WordRule;
+
+/**
+ * Processing uses Java comments, so we use the same scanner. The class name is
+ * changed for consistency.
+ *
+ * This scanner recognizes the JavaDoc comments and Java multi line comments.
+ */
+public class ProcessingPartitionScanner extends RuleBasedPartitionScanner {
+
+ public final static String JAVA_MULTILINE_COMMENT= "__java_multiline_comment"; //$NON-NLS-1$
+ //Removing JavaDoc support from sketches, but leave in code
+// public final static String JAVA_DOC= "__java_javadoc"; //$NON-NLS-1$
+// public final static String[] JAVA_PARTITION_TYPES= new String[] { JAVA_MULTILINE_COMMENT, JAVA_DOC };
+ public final static String[] JAVA_PARTITION_TYPES= new String[] { JAVA_MULTILINE_COMMENT };
+
+ /**
+ * Detector for empty comments.
+ */
+ static class EmptyCommentDetector implements IWordDetector {
+
+ /* (non-Javadoc)
+ * Method declared on IWordDetector
+ */
+ public boolean isWordStart(char c) {
+ return (c == '/');
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IWordDetector
+ */
+ public boolean isWordPart(char c) {
+ return (c == '*' || c == '/');
+ }
+ }
+
+ /**
+ *
+ */
+ static class WordPredicateRule extends WordRule implements IPredicateRule {
+
+ private IToken fSuccessToken;
+
+ public WordPredicateRule(IToken successToken) {
+ super(new EmptyCommentDetector());
+ fSuccessToken= successToken;
+ addWord("/**/", fSuccessToken); //$NON-NLS-1$
+ }
+
+ /*
+ * @see org.eclipse.jface.text.rules.IPredicateRule#evaluate(ICharacterScanner, boolean)
+ */
+ public IToken evaluate(ICharacterScanner scanner, boolean resume) {
+ return super.evaluate(scanner);
+ }
+
+ /*
+ * @see org.eclipse.jface.text.rules.IPredicateRule#getSuccessToken()
+ */
+ public IToken getSuccessToken() {
+ return fSuccessToken;
+ }
+ }
+
+ /**
+ * Creates the partitioner and sets up the appropriate rules.
+ */
+ public ProcessingPartitionScanner() {
+ super();
+ //Removing JavaDoc support from sketches, but leave in code
+// IToken javaDoc= new Token(JAVA_DOC);
+ IToken comment= new Token(JAVA_MULTILINE_COMMENT);
+
+ List rules= new ArrayList();
+
+ // Add rule for single line comments.
+ rules.add(new EndOfLineRule("//", Token.UNDEFINED)); //$NON-NLS-1$
+
+ // Add rule for strings and character constants.
+ rules.add(new SingleLineRule("\"", "\"", Token.UNDEFINED, '\\')); //$NON-NLS-2$ //$NON-NLS-1$
+ rules.add(new SingleLineRule("'", "'", Token.UNDEFINED, '\\')); //$NON-NLS-2$ //$NON-NLS-1$
+
+ // Add special case word rule.
+ rules.add(new WordPredicateRule(comment));
+
+ // Add rules for multi-line comments and javadoc.
+ //Removing JavaDoc support from sketches, but leave in code
+// rules.add(new MultiLineRule("/**", "*/", javaDoc, (char) 0, true)); //$NON-NLS-1$ //$NON-NLS-2$
+ rules.add(new MultiLineRule("/*", "*/", comment, (char) 0, true)); //$NON-NLS-1$ //$NON-NLS-2$
+
+ IPredicateRule[] result= new IPredicateRule[rules.size()];
+ rules.toArray(result);
+ setPredicateRules(result);
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/ProcessingSourceViewerConfiguration.java b/editor/org.processing.editor/src/org/processing/editor/ProcessingSourceViewerConfiguration.java
new file mode 100644
index 000000000..aff27dbf7
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/ProcessingSourceViewerConfiguration.java
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor;
+
+import org.eclipse.jface.text.DefaultIndentLineAutoEditStrategy;
+import org.eclipse.jface.text.IAutoEditStrategy;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextDoubleClickStrategy;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.TextAttribute;
+import org.eclipse.jface.text.contentassist.ContentAssistant;
+import org.eclipse.jface.text.contentassist.IContentAssistant;
+import org.eclipse.jface.text.presentation.IPresentationReconciler;
+import org.eclipse.jface.text.presentation.PresentationReconciler;
+import org.eclipse.jface.text.rules.BufferedRuleBasedScanner;
+import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
+import org.eclipse.jface.text.rules.Token;
+import org.eclipse.jface.text.source.IAnnotationHover;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.SourceViewerConfiguration;
+import org.eclipse.swt.graphics.RGB;
+import org.processing.editor.language.ProcessingAutoIndentStrategy;
+import org.processing.editor.language.ProcessingCompletionProcessor;
+import org.processing.editor.language.ProcessingDoubleClickSelector;
+import org.processing.editor.util.ProcessingColorProvider;
+
+/**
+ * Configuration for the ProcessingSourceViewer.
+ */
+public class ProcessingSourceViewerConfiguration extends SourceViewerConfiguration {
+
+ /**
+ * Single token scanner.
+ */
+ static class SingleTokenScanner extends BufferedRuleBasedScanner {
+ public SingleTokenScanner(TextAttribute attribute) {
+ setDefaultReturnToken(new Token(attribute));
+ }
+ }
+
+ /**
+ * Default constructor.
+ */
+ public ProcessingSourceViewerConfiguration() {
+ }
+
+ /* (non-Javadoc)
+ * Method declared on SourceViewerConfiguration
+ */
+ public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer) {
+ return new ProcessingAnnotationHover();
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getAutoEditStrategies(org.eclipse.jface.text.source.ISourceViewer, java.lang.String)
+ */
+ public IAutoEditStrategy[] getAutoEditStrategies(ISourceViewer sourceViewer, String contentType) {
+ IAutoEditStrategy strategy= (IDocument.DEFAULT_CONTENT_TYPE.equals(contentType) ? new ProcessingAutoIndentStrategy() : new DefaultIndentLineAutoEditStrategy());
+ return new IAutoEditStrategy[] { strategy };
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getConfiguredDocumentPartitioning(org.eclipse.jface.text.source.ISourceViewer)
+ */
+ public String getConfiguredDocumentPartitioning(ISourceViewer sourceViewer) {
+ return ProcessingEditorPlugin.PROCESSING_PARTITIONING;
+ }
+
+ /* (non-Javadoc)
+ * Method declared on SourceViewerConfiguration
+ */
+ public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) {
+ //Removing JavaDoc support from sketches, but leave in code
+ //return new String[] { IDocument.DEFAULT_CONTENT_TYPE, ProcessingPartitionScanner.JAVA_DOC, ProcessingPartitionScanner.JAVA_MULTILINE_COMMENT };
+ return new String[] { IDocument.DEFAULT_CONTENT_TYPE, ProcessingPartitionScanner.JAVA_MULTILINE_COMMENT };
+ }
+
+ /* (non-Javadoc)
+ * Method declared on SourceViewerConfiguration
+ */
+ public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
+
+ ContentAssistant assistant= new ContentAssistant();
+ assistant.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer));
+ assistant.setContentAssistProcessor(new ProcessingCompletionProcessor(), IDocument.DEFAULT_CONTENT_TYPE);
+ // Disabling JavaDoc support [lonnen] june 12 2010
+ //assistant.setContentAssistProcessor(new JavaDocCompletionProcessor(), ProcessingPartitionScanner.JAVA_DOC);
+
+ assistant.enableAutoActivation(true);
+ assistant.setAutoActivationDelay(500);
+ assistant.setProposalPopupOrientation(IContentAssistant.PROPOSAL_OVERLAY);
+ assistant.setContextInformationPopupOrientation(IContentAssistant.CONTEXT_INFO_ABOVE);
+ assistant.setContextInformationPopupBackground(ProcessingEditorPlugin.getDefault().getProcessingColorProvider().getColor(new RGB(150, 150, 0)));
+
+ return assistant;
+ }
+
+ /* (non-Javadoc)
+ * Method declared on SourceViewerConfiguration
+ */
+ public String getDefaultPrefix(ISourceViewer sourceViewer, String contentType) {
+ return (IDocument.DEFAULT_CONTENT_TYPE.equals(contentType) ? "//" : null); //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * Method declared on SourceViewerConfiguration
+ */
+ public ITextDoubleClickStrategy getDoubleClickStrategy(ISourceViewer sourceViewer, String contentType) {
+ return new ProcessingDoubleClickSelector();
+ }
+
+ /* (non-Javadoc)
+ * Method declared on SourceViewerConfiguration
+ */
+ public String[] getIndentPrefixes(ISourceViewer sourceViewer, String contentType) {
+ return new String[] { "\t", " " }; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /* (non-Javadoc)
+ * Method declared on SourceViewerConfiguration
+ */
+ public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {
+
+ ProcessingColorProvider provider= ProcessingEditorPlugin.getDefault().getProcessingColorProvider();
+
+ PresentationReconciler reconciler= new PresentationReconciler();
+ reconciler.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer));
+
+ DefaultDamagerRepairer dr= new DefaultDamagerRepairer(ProcessingEditorPlugin.getDefault().getProcessingCodeScanner());
+ reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
+ reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
+
+ //Removing JavaDoc support from sketches, but leave in code
+// dr= new DefaultDamagerRepairer(ProcessingEditorPlugin.getDefault().getProcessingDocScanner());
+// reconciler.setDamager(dr, ProcessingPartitionScanner.JAVA_DOC);
+// reconciler.setRepairer(dr, ProcessingPartitionScanner.JAVA_DOC);
+
+ dr= new DefaultDamagerRepairer(new SingleTokenScanner(new TextAttribute(provider.getColor(ProcessingColorProvider.COMMENT1))));
+ reconciler.setDamager(dr, ProcessingPartitionScanner.JAVA_MULTILINE_COMMENT);
+ reconciler.setRepairer(dr, ProcessingPartitionScanner.JAVA_MULTILINE_COMMENT);
+
+ return reconciler;
+ }
+
+ /* (non-Javadoc)
+ * Method declared on SourceViewerConfiguration
+ */
+ public int getTabWidth(ISourceViewer sourceViewer) {
+ return 4;
+ }
+
+ /* (non-Javadoc)
+ * Method declared on SourceViewerConfiguration
+ */
+ public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) {
+ return new ProcessingTextHover();
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/ProcessingTextHover.java b/editor/org.processing.editor/src/org/processing/editor/ProcessingTextHover.java
new file mode 100644
index 000000000..8cecda67b
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/ProcessingTextHover.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor;
+
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Region;
+import org.eclipse.swt.graphics.Point;
+
+/**
+ * Example implementation for an ITextHover which hovers over Java code.
+ */
+public class ProcessingTextHover implements ITextHover {
+
+ /* (non-Javadoc)
+ * Method declared on ITextHover
+ */
+ public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
+ if (hoverRegion != null) {
+ try {
+ if (hoverRegion.getLength() > -1)
+ //TODO Implement a hover that returns something useful
+ return textViewer.getDocument().get(hoverRegion.getOffset(), hoverRegion.getLength());
+ } catch (BadLocationException x) {
+ }
+ }
+ return ProcessingEditorMessages.getString("ProcessingTextHover.emptySelection"); //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * Method declared on ITextHover
+ */
+ public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
+ Point selection= textViewer.getSelectedRange();
+ if (selection.x <= offset && offset < selection.x + selection.y)
+ return new Region(selection.x, selection.y);
+ return new Region(offset, 0);
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/javadoc/JavaDocCompletionProcessor.java b/editor/org.processing.editor/src/org/processing/editor/javadoc/JavaDocCompletionProcessor.java
new file mode 100644
index 000000000..32aad9f20
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/javadoc/JavaDocCompletionProcessor.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor.javadoc;
+
+
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.contentassist.CompletionProposal;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.text.contentassist.IContextInformationValidator;
+
+/**
+ * Example Java doc completion processor. Should work for Processing unmodified. Do we even use Javadoc?
+ */
+public class JavaDocCompletionProcessor implements IContentAssistProcessor {
+
+ protected final static String[] fgProposals= { "@author", "@deprecated", "@exception", "@param", "@return", "@see", "@serial", "@serialData", "@serialField", "@since", "@throws", "@version" }; //$NON-NLS-12$ //$NON-NLS-11$ //$NON-NLS-10$ //$NON-NLS-7$ //$NON-NLS-9$ //$NON-NLS-8$ //$NON-NLS-6$ //$NON-NLS-5$ //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
+
+ /* (non-Javadoc)
+ * Method declared on IContentAssistProcessor
+ */
+ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentOffset) {
+ ICompletionProposal[] result= new ICompletionProposal[fgProposals.length];
+ for (int i= 0; i < fgProposals.length; i++)
+ result[i]= new CompletionProposal(fgProposals[i], documentOffset, 0, fgProposals[i].length());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IContentAssistProcessor
+ */
+ public IContextInformation[] computeContextInformation(ITextViewer viewer, int documentOffset) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IContentAssistProcessor
+ */
+ public char[] getCompletionProposalAutoActivationCharacters() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IContentAssistProcessor
+ */
+ public char[] getContextInformationAutoActivationCharacters() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IContentAssistProcessor
+ */
+ public IContextInformationValidator getContextInformationValidator() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IContentAssistProcessor
+ */
+ public String getErrorMessage() {
+ return null;
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/javadoc/JavaDocScanner.java b/editor/org.processing.editor/src/org/processing/editor/javadoc/JavaDocScanner.java
new file mode 100644
index 000000000..765c9327d
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/javadoc/JavaDocScanner.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor.javadoc;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.text.TextAttribute;
+import org.eclipse.jface.text.rules.IRule;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.IWordDetector;
+import org.eclipse.jface.text.rules.RuleBasedScanner;
+import org.eclipse.jface.text.rules.SingleLineRule;
+import org.eclipse.jface.text.rules.Token;
+import org.eclipse.jface.text.rules.WhitespaceRule;
+import org.eclipse.jface.text.rules.WordRule;
+import org.processing.editor.util.ProcessingColorProvider;
+import org.processing.editor.util.ProcessingWhitespaceDetector;
+
+
+/**
+ * A rule based JavaDoc scanner.
+ */
+public class JavaDocScanner extends RuleBasedScanner {
+
+ /**
+ * A key word detector.
+ */
+ static class JavaDocWordDetector implements IWordDetector {
+
+ /* (non-Javadoc)
+ * Method declared on IWordDetector
+ */
+ public boolean isWordStart(char c) {
+ return (c == '@');
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IWordDetector
+ */
+ public boolean isWordPart(char c) {
+ return Character.isLetter(c);
+ }
+ }
+
+ private static String[] fgKeywords= { "@author", "@deprecated", "@exception", "@param", "@return", "@see", "@serial", "@serialData", "@serialField", "@since", "@throws", "@version" }; //$NON-NLS-12$ //$NON-NLS-11$ //$NON-NLS-10$ //$NON-NLS-7$ //$NON-NLS-9$ //$NON-NLS-8$ //$NON-NLS-6$ //$NON-NLS-5$ //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
+
+ /**
+ * Create a new javadoc scanner for the given color provider.
+ *
+ * @param provider the color provider
+ */
+ public JavaDocScanner(ProcessingColorProvider provider) {
+ super();
+
+ IToken keyword= new Token(new TextAttribute(provider.getColor(ProcessingColorProvider.JAVADOC_KEYWORD)));
+ IToken tag= new Token(new TextAttribute(provider.getColor(ProcessingColorProvider.JAVADOC_TAG)));
+ IToken link= new Token(new TextAttribute(provider.getColor(ProcessingColorProvider.JAVADOC_LINK)));
+
+ List list= new ArrayList();
+
+ // Add rule for tags.
+ list.add(new SingleLineRule("<", ">", tag)); //$NON-NLS-2$ //$NON-NLS-1$
+
+ // Add rule for links.
+ list.add(new SingleLineRule("{", "}", link)); //$NON-NLS-2$ //$NON-NLS-1$
+
+ // Add generic whitespace rule.
+ list.add(new WhitespaceRule(new ProcessingWhitespaceDetector()));
+
+ // Add word rule for keywords.
+ WordRule wordRule= new WordRule(new JavaDocWordDetector());
+ for (int i= 0; i < fgKeywords.length; i++)
+ wordRule.addWord(fgKeywords[i], keyword);
+ list.add(wordRule);
+
+ IRule[] result= new IRule[list.size()];
+ list.toArray(result);
+ setRules(result);
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/language/ProcessingAutoIndentStrategy.java b/editor/org.processing.editor/src/org/processing/editor/language/ProcessingAutoIndentStrategy.java
new file mode 100644
index 000000000..449cef152
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/language/ProcessingAutoIndentStrategy.java
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor.language;
+
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DefaultIndentLineAutoEditStrategy;
+import org.eclipse.jface.text.DocumentCommand;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.TextUtilities;
+
+/**
+ * Auto indent line strategy sensitive to brackets. Should work for Processing unmodified.
+ */
+public class ProcessingAutoIndentStrategy extends DefaultIndentLineAutoEditStrategy {
+
+ public ProcessingAutoIndentStrategy() {
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IAutoIndentStrategy
+ */
+ public void customizeDocumentCommand(IDocument d, DocumentCommand c) {
+ if (c.length == 0 && c.text != null && endsWithDelimiter(d, c.text))
+ smartIndentAfterNewLine(d, c);
+ else if ("}".equals(c.text)) { //$NON-NLS-1$
+ smartInsertAfterBracket(d, c);
+ }
+ }
+
+ /**
+ * Returns whether or not the given text ends with one of the documents legal line delimiters.
+ *
+ * @param d the document
+ * @param txt the text
+ * @return true if txt ends with one of the document's line delimiters, false otherwise
+ */
+ private boolean endsWithDelimiter(IDocument d, String txt) {
+ String[] delimiters= d.getLegalLineDelimiters();
+ if (delimiters != null)
+ return TextUtilities.endsWith(delimiters, txt) > -1;
+ return false;
+ }
+
+ /**
+ * Returns the line number of the next bracket after end.
+ *
+ * @param document - the document being parsed
+ * @param line - the line to start searching back from
+ * @param end - the end position to search back from
+ * @param closingBracketIncrease - the number of brackets to skip
+ * @return the line number of the next matching bracket after end
+ * @throws BadLocationException in case the line numbers are invalid in the document
+ */
+ protected int findMatchingOpenBracket(IDocument document, int line, int end, int closingBracketIncrease) throws BadLocationException {
+
+ int start= document.getLineOffset(line);
+ int brackcount= getBracketCount(document, start, end, false) - closingBracketIncrease;
+
+ // sum up the brackets counts of each line (closing brackets count negative,
+ // opening positive) until we find a line the brings the count to zero
+ while (brackcount < 0) {
+ line--;
+ if (line < 0) {
+ return -1;
+ }
+ start= document.getLineOffset(line);
+ end= start + document.getLineLength(line) - 1;
+ brackcount += getBracketCount(document, start, end, false);
+ }
+ return line;
+ }
+
+ /**
+ * Returns the bracket value of a section of text. Closing brackets have a value of -1 and
+ * open brackets have a value of 1.
+ *
+ * @param document - the document being parsed
+ * @param start - the start position for the search
+ * @param end - the end position for the search
+ * @param ignoreCloseBrackets - whether or not to ignore closing brackets in the count
+ * @return the bracket value of a section of text
+ * @throws BadLocationException in case the positions are invalid in the document
+ */
+ private int getBracketCount(IDocument document, int start, int end, boolean ignoreCloseBrackets) throws BadLocationException {
+
+ int begin = start;
+ int bracketcount= 0;
+ while (begin < end) {
+ char curr= document.getChar(begin);
+ begin++;
+ switch (curr) {
+ case '/' :
+ if (begin < end) {
+ char next= document.getChar(begin);
+ if (next == '*') {
+ // a comment starts, advance to the comment end
+ begin= getCommentEnd(document, begin + 1, end);
+ } else if (next == '/') {
+ // '//'-comment: nothing to do anymore on this line
+ begin= end;
+ }
+ }
+ break;
+ case '*' :
+ if (begin < end) {
+ char next= document.getChar(begin);
+ if (next == '/') {
+ // we have been in a comment: forget what we read before
+ bracketcount= 0;
+ begin++;
+ }
+ }
+ break;
+ case '{' :
+ bracketcount++;
+ ignoreCloseBrackets= false;
+ break;
+ case '}' :
+ if (!ignoreCloseBrackets) {
+ bracketcount--;
+ }
+ break;
+ case '"' :
+ case '\'' :
+ begin= getStringEnd(document, begin, end, curr);
+ break;
+ default :
+ }
+ }
+ return bracketcount;
+ }
+
+ /**
+ * Returns the end position of a comment starting at the given position.
+ *
+ * @param document - the document being parsed
+ * @param position - the start position for the search
+ * @param end - the end position for the search
+ * @return the end position of a comment starting at the given position
+ * @throws BadLocationException in case position and end are invalid in the document
+ */
+ private int getCommentEnd(IDocument document, int position, int end) throws BadLocationException {
+ int currentPosition = position;
+ while (currentPosition < end) {
+ char curr= document.getChar(currentPosition);
+ currentPosition++;
+ if (curr == '*') {
+ if (currentPosition < end && document.getChar(currentPosition) == '/') {
+ return currentPosition + 1;
+ }
+ }
+ }
+ return end;
+ }
+
+ /**
+ * Returns the content of the given line without the leading whitespace.
+ *
+ * @param document - the document being parsed
+ * @param line - the line being searched
+ * @return the content of the given line without the leading whitespace
+ * @throws BadLocationException in case line is invalid in the document
+ */
+ protected String getIndentOfLine(IDocument document, int line) throws BadLocationException {
+ if (line > -1) {
+ int start= document.getLineOffset(line);
+ int end= start + document.getLineLength(line) - 1;
+ int whiteend= findEndOfWhiteSpace(document, start, end);
+ return document.get(start, whiteend - start);
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the position of the character in the document after position.
+ *
+ * @param document - the document being parsed
+ * @param position - the position to start searching from
+ * @param end - the end of the document
+ * @param character - the character you are trying to match
+ * @return the next location of character
+ * @throws BadLocationException in case position is invalid in the document
+ */
+ private int getStringEnd(IDocument document, int position, int end, char character) throws BadLocationException {
+ int currentPosition = position;
+ while (currentPosition < end) {
+ char currentCharacter= document.getChar(currentPosition);
+ currentPosition++;
+ if (currentCharacter == '\\') {
+ // ignore escaped characters
+ currentPosition++;
+ } else if (currentCharacter == character) {
+ return currentPosition;
+ }
+ }
+ return end;
+ }
+
+ /**
+ * Set the indent of a new line based on the command provided in the supplied document.
+ * @param document - the document being parsed
+ * @param command - the command being performed
+ */
+ protected void smartIndentAfterNewLine(IDocument document, DocumentCommand command) {
+
+ int docLength= document.getLength();
+ if (command.offset == -1 || docLength == 0)
+ return;
+
+ try {
+ int p= (command.offset == docLength ? command.offset - 1 : command.offset);
+ int line= document.getLineOfOffset(p);
+
+ StringBuffer buf= new StringBuffer(command.text);
+ if (command.offset < docLength && document.getChar(command.offset) == '}') {
+ int indLine= findMatchingOpenBracket(document, line, command.offset, 0);
+ if (indLine == -1) {
+ indLine= line;
+ }
+ buf.append(getIndentOfLine(document, indLine));
+ } else {
+ int start= document.getLineOffset(line);
+ int whiteend= findEndOfWhiteSpace(document, start, command.offset);
+ buf.append(document.get(start, whiteend - start));
+ if (getBracketCount(document, start, command.offset, true) > 0) {
+ buf.append('\t');
+ }
+ }
+ command.text= buf.toString();
+
+ } catch (BadLocationException excp) {
+ System.out.println(ProcessingEditorMessages.getString("AutoIndent.error.bad_location_1")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Set the indent of a bracket based on the command provided in the supplied document.
+ * @param document - the document being parsed
+ * @param command - the command being performed
+ */
+ protected void smartInsertAfterBracket(IDocument document, DocumentCommand command) {
+ if (command.offset == -1 || document.getLength() == 0)
+ return;
+
+ try {
+ int p= (command.offset == document.getLength() ? command.offset - 1 : command.offset);
+ int line= document.getLineOfOffset(p);
+ int start= document.getLineOffset(line);
+ int whiteend= findEndOfWhiteSpace(document, start, command.offset);
+
+ // shift only when line does not contain any text up to the closing bracket
+ if (whiteend == command.offset) {
+ // evaluate the line with the opening bracket that matches out closing bracket
+ int indLine= findMatchingOpenBracket(document, line, command.offset, 1);
+ if (indLine != -1 && indLine != line) {
+ // take the indent of the found line
+ StringBuffer replaceText= new StringBuffer(getIndentOfLine(document, indLine));
+ // add the rest of the current line including the just added close bracket
+ replaceText.append(document.get(whiteend, command.offset - whiteend));
+ replaceText.append(command.text);
+ // modify document command
+ command.length= command.offset - start;
+ command.offset= start;
+ command.text= replaceText.toString();
+ }
+ }
+ } catch (BadLocationException excp) {
+ System.out.println(ProcessingEditorMessages.getString("AutoIndent.error.bad_location_2")); //$NON-NLS-1$
+ }
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/language/ProcessingCodeScanner.java b/editor/org.processing.editor/src/org/processing/editor/language/ProcessingCodeScanner.java
new file mode 100644
index 000000000..8e7ca492e
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/language/ProcessingCodeScanner.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor.language;
+
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.text.TextAttribute;
+import org.eclipse.jface.text.rules.EndOfLineRule;
+import org.eclipse.jface.text.rules.IRule;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.RuleBasedScanner;
+import org.eclipse.jface.text.rules.SingleLineRule;
+import org.eclipse.jface.text.rules.Token;
+import org.eclipse.jface.text.rules.WhitespaceRule;
+import org.eclipse.jface.text.rules.WordRule;
+import org.processing.editor.ProcessingEditorPlugin;
+import org.processing.editor.util.ProcessingColorProvider;
+import org.processing.editor.util.ProcessingWhitespaceDetector;
+import org.processing.editor.util.ProcessingWordDetector;
+
+/**
+ * A Processing code scanner.
+ */
+public class ProcessingCodeScanner extends RuleBasedScanner {
+
+ private static String keywordsFile = "keywords.txt"; // name of the syntax highlighting file
+
+ private static String[] fgKeywords1; // keywords (new, return, super)
+ private static String[] fgKeywords2; // PDE methods (setup, random, size)
+ private static String[] fgKeywords3; // primitive types (int, color, float)
+ private static String[] fgLiterals1; // static tokens (null, true, P2D)
+ private static String[] fgLiterals2; // environmental variables (mouseX, width, pixels)
+ private static String[] fgLabels; // possibly unused? Supporting them here because Processing does.
+ private static String[] fgOperators; // mathematical operators (+, -, *)
+ private static String[] fgInvalids; // possibly unused? Supporting them here because Processing does.
+
+ /*
+ * Static initialization block to load Processing Keywords in from keywords.txt
+ * This is similar to the way the Processing Developer Environment loads keywords
+ * for syntax highlighting.
+ *
+ * Reads in the keyword file and splits each line at the tabs. The first string
+ * is the symbol, the second is the category (empty strings indicate operators)
+ * and the third string is ignored. In Processing it is used to lookup reference
+ * HTML.
+ *
+ * A HashMap stores each category as a key corresponding to a HashSet value that
+ * holds the tokens belonging to each category. After the keywordsFile is
+ * processed, the HashMap sets are converted to string arrays and loaded into the
+ * static keyword lists the document expects. At the moment each set of keywords
+ * we create rules for are explicitly listed. If the keywords categories change in
+ * the future, there will need to new categories introduced in the code scanner
+ * and ProcessingColorProvider.
+ *
+ * Unexpected categories in the keywords file will be silently ignored.
+ * 'Unsure of how to JavaDoc an init block so I did this' - [lonnen] june 16, 2010
+ */
+ static {
+ HashMaptrue if successful,
+ * false otherwise.
+ *
+ * @return true if brackets match, false otherwise
+ */
+ protected boolean matchBracketsAt() {
+
+ char prevChar, nextChar;
+
+ int i;
+ int bracketIndex1= fgBrackets.length;
+ int bracketIndex2= fgBrackets.length;
+
+ fStartPos= -1;
+ fEndPos= -1;
+
+ // get the chars preceding and following the start position
+ try {
+
+ IDocument doc= fText.getDocument();
+
+ prevChar= doc.getChar(fPos - 1);
+ nextChar= doc.getChar(fPos);
+
+ // is the char either an open or close bracket?
+ for (i= 0; i < fgBrackets.length; i= i + 2) {
+ if (prevChar == fgBrackets[i]) {
+ fStartPos= fPos - 1;
+ bracketIndex1= i;
+ }
+ }
+ for (i= 1; i < fgBrackets.length; i= i + 2) {
+ if (nextChar == fgBrackets[i]) {
+ fEndPos= fPos;
+ bracketIndex2= i;
+ }
+ }
+
+ if (fStartPos > -1 && bracketIndex1 < bracketIndex2) {
+ fEndPos= searchForClosingBracket(fStartPos, prevChar, fgBrackets[bracketIndex1 + 1], doc);
+ if (fEndPos > -1)
+ return true;
+ fStartPos= -1;
+ } else if (fEndPos > -1) {
+ fStartPos= searchForOpenBracket(fEndPos, fgBrackets[bracketIndex2 - 1], nextChar, doc);
+ if (fStartPos > -1)
+ return true;
+ fEndPos= -1;
+ }
+
+ } catch (BadLocationException x) {
+ }
+
+ return false;
+ }
+
+ /**
+ * Select the word at the current selection location. Return true if successful,
+ * false otherwise.
+ *
+ * @return true if a word can be found at the current selection location, false otherwise
+ */
+ protected boolean matchWord() {
+
+ IDocument doc= fText.getDocument();
+
+ try {
+
+ int pos= fPos;
+ char c;
+
+ while (pos >= 0) {
+ c= doc.getChar(pos);
+ if (!Character.isJavaIdentifierPart(c))
+ break;
+ --pos;
+ }
+
+ fStartPos= pos;
+
+ pos= fPos;
+ int length= doc.getLength();
+
+ while (pos < length) {
+ c= doc.getChar(pos);
+ if (!Character.isJavaIdentifierPart(c))
+ break;
+ ++pos;
+ }
+
+ fEndPos= pos;
+
+ return true;
+
+ } catch (BadLocationException x) {
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the position of the closing bracket after startPosition.
+ *
+ * @param startPosition - the beginning position
+ * @param openBracket - the character that represents the open bracket
+ * @param closeBracket - the character that represents the close bracket
+ * @param document - the document being searched
+ * @return the location of the closing bracket.
+ * @throws BadLocationException in case startPosition is invalid in the document
+ */
+ protected int searchForClosingBracket(int startPosition, char openBracket, char closeBracket, IDocument document) throws BadLocationException {
+ int stack= 1;
+ int closePosition= startPosition + 1;
+ int length= document.getLength();
+ char nextChar;
+
+ while (closePosition < length && stack > 0) {
+ nextChar= document.getChar(closePosition);
+ if (nextChar == openBracket && nextChar != closeBracket)
+ stack++;
+ else if (nextChar == closeBracket)
+ stack--;
+ closePosition++;
+ }
+
+ if (stack == 0)
+ return closePosition - 1;
+ return -1;
+
+ }
+
+ /**
+ * Returns the position of the open bracket before startPosition.
+ *
+ * @param startPosition - the beginning position
+ * @param openBracket - the character that represents the open bracket
+ * @param closeBracket - the character that represents the close bracket
+ * @param document - the document being searched
+ * @return the location of the starting bracket.
+ * @throws BadLocationException in case startPosition is invalid in the document
+ */
+ protected int searchForOpenBracket(int startPosition, char openBracket, char closeBracket, IDocument document) throws BadLocationException {
+ int stack= 1;
+ int openPos= startPosition - 1;
+ char nextChar;
+
+ while (openPos >= 0 && stack > 0) {
+ nextChar= document.getChar(openPos);
+ if (nextChar == closeBracket && nextChar != openBracket)
+ stack++;
+ else if (nextChar == openBracket)
+ stack--;
+ openPos--;
+ }
+
+ if (stack == 0)
+ return openPos + 1;
+ return -1;
+ }
+
+ /**
+ * Select the area between the selected bracket and the closing bracket.
+ *
+ * @return true if selection was successful, false otherwise
+ */
+ protected boolean selectBracketBlock() {
+ if (matchBracketsAt()) {
+
+ if (fStartPos == fEndPos)
+ fText.setSelectedRange(fStartPos, 0);
+ else
+ fText.setSelectedRange(fStartPos + 1, fEndPos - fStartPos - 1);
+
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Select the word at the current selection.
+ */
+ protected void selectWord() {
+ if (matchWord()) {
+
+ if (fStartPos == fEndPos)
+ fText.setSelectedRange(fStartPos, 0);
+ else
+ fText.setSelectedRange(fStartPos + 1, fEndPos - fStartPos - 1);
+ }
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/language/ProcessingEditorMessages.java b/editor/org.processing.editor/src/org/processing/editor/language/ProcessingEditorMessages.java
new file mode 100644
index 000000000..79f7f86b4
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/language/ProcessingEditorMessages.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor.language;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class ProcessingEditorMessages {
+
+ private static final String RESOURCE_BUNDLE= "org.processing.editor.ProcessingEditorMessages";//$NON-NLS-1$
+
+ private static ResourceBundle fgResourceBundle= ResourceBundle.getBundle(RESOURCE_BUNDLE);
+
+ private ProcessingEditorMessages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return fgResourceBundle.getString(key);
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/util/ProcessingColorProvider.java b/editor/org.processing.editor/src/org/processing/editor/util/ProcessingColorProvider.java
new file mode 100644
index 000000000..4ac3b9b3b
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/util/ProcessingColorProvider.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor.util;
+
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Manager for colors used in the Java editor
+ */
+public class ProcessingColorProvider {
+
+ public static final RGB COMMENT1= new RGB(126, 126, 126); //comment 1
+ public static final RGB COMMENT2= new RGB(126, 126, 126); //comment 2
+ public static final RGB KEYWORD1= new RGB(204, 102, 0);
+ public static final RGB KEYWORD2= new RGB(204, 102, 0);
+ public static final RGB KEYWORD3= new RGB(204, 102, 0);
+ public static final RGB LITERAL1= new RGB(0, 102, 153); // currently unused [lonnen] june 16, 2010
+ public static final RGB LITERAL2= new RGB(0, 102, 153);
+ public static final RGB LABEL= new RGB(0, 0, 128); // use listed as '?' in p5 doc
+ public static final RGB OPERATOR= new RGB(0, 0, 0);
+ public static final RGB INVALID= new RGB(126, 126, 126); // never used [lonnen] june 16, 2010
+ public static final RGB STRING= new RGB(0, 102, 153);
+ public static final RGB DEFAULT= new RGB(0, 0, 0);
+
+ // used to color JavaDoc by org.processing.editor.javadoc.JavaDocScanner
+ // currently ignored, as JavaDoc is treated like normal multiline comments
+ // left available to avoid compiler errors from the JavaDocScanner.java class
+ // which is never instantiated but wants access to them anyway because the
+ // compiler doesn't realize these things. [lonnen] june 16, 2010
+ public static final RGB JAVADOC_KEYWORD= new RGB(126, 126, 126);
+ public static final RGB JAVADOC_TAG= new RGB(126, 126, 126);
+ public static final RGB JAVADOC_LINK= new RGB(126, 126, 126);
+ public static final RGB JAVADOC_DEFAULT= new RGB(126, 126, 126);
+
+ protected Map fColorTable= new HashMap(17);
+
+ /**
+ * Release all of the color resources held onto by the receiver.
+ */
+ public void dispose() {
+ Iterator e= fColorTable.values().iterator();
+ while (e.hasNext())
+ ((Color) e.next()).dispose();
+ }
+
+ /**
+ * Return the color that is stored in the color table under the given RGB
+ * value.
+ *
+ * @param rgb the RGB value
+ * @return the color stored in the color table for the given RGB value
+ */
+ public Color getColor(RGB rgb) {
+ Color color= (Color) fColorTable.get(rgb);
+ if (color == null) {
+ color= new Color(Display.getCurrent(), rgb);
+ fColorTable.put(rgb, color);
+ }
+ return color;
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/util/ProcessingWhitespaceDetector.java b/editor/org.processing.editor/src/org/processing/editor/util/ProcessingWhitespaceDetector.java
new file mode 100644
index 000000000..93c328433
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/util/ProcessingWhitespaceDetector.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor.util;
+
+
+import org.eclipse.jface.text.rules.IWhitespaceDetector;
+
+/**
+ * A Processing aware white space detector, same as a java aware white space detector.
+ */
+public class ProcessingWhitespaceDetector implements IWhitespaceDetector {
+
+ /* (non-Javadoc)
+ * Method declared on IWhitespaceDetector
+ */
+ public boolean isWhitespace(char character) {
+ return Character.isWhitespace(character);
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/editor/util/ProcessingWordDetector.java b/editor/org.processing.editor/src/org/processing/editor/util/ProcessingWordDetector.java
new file mode 100644
index 000000000..3b42dadea
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/editor/util/ProcessingWordDetector.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.processing.editor.util;
+
+
+import org.eclipse.jface.text.rules.IWordDetector;
+
+/**
+ * A Processing aware word detector. Same as a java aware word detector.
+ */
+public class ProcessingWordDetector implements IWordDetector {
+
+ /* (non-Javadoc)
+ * Method declared on IWordDetector.
+ */
+ public boolean isWordPart(char character) {
+ return Character.isJavaIdentifierPart(character);
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IWordDetector.
+ */
+ public boolean isWordStart(char character) {
+ return Character.isJavaIdentifierStart(character);
+ }
+}
diff --git a/editor/org.processing.editor/src/org/processing/preferences/PreferenceConstants.java b/editor/org.processing.editor/src/org/processing/preferences/PreferenceConstants.java
new file mode 100644
index 000000000..be9b58470
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/preferences/PreferenceConstants.java
@@ -0,0 +1,28 @@
+package org.processing.preferences;
+
+/**
+ * Constant definitions for plug-in preferences
+ */
+public class PreferenceConstants {
+
+ // Editor Preferences
+ public static final String PROCESSING_SKETCHBOOK = "sketch_path"; // path preference
+ public static final String PROCESSING_LIBRARIES = "library_path"; // path preference
+ public static final String PROCESSING_AUTO_INDENT = "eclipse.editor.auto.indent";
+
+// // PROCESSING_PREFERENCES prefix indicates membership in the processing.app preferences class
+// public static final String PROCESSING_APP_PREFERENCES_EDITOR_TABS_SIZE = "editor.tabs.size";
+// public static final String PROCESSING_APP_PREFERENCES_PREPROC_SUBSTITUTE_FLOATS= "preproc.substitute_floats";
+// public static final String PROCESSING_APP_PREFERENCES_PREPROC_WEB_COLORS = "preproc.web_colors";
+// public static final String PROCESSING_APP_PREFERENCES_PREPROC_COLOR_DATATYPE = "preproc.color_datatype";
+// public static final String PROCESSING_APP_PREFERENCES_PREPROC_ENHANCED_CASTING = "preproc.enhanced_casted";
+// public static final String PROCESSING_APP_PREFERENCES_PREPROC_SUBSTITUTE_UNICODE = "preproc.substitute.unicode";
+// public static final String PROCESSING_APP_PREFERENCES_PREPROC_OUTPUT_PARSE_TREE = "preproc.output_parse.tree";
+// public static final String PROCESSING_APP_PREFERENCES_PREPROC_EXPORT_APPLICATION_FULLSCREEN = "export.application.fullscreen";
+// public static final String PROCESSING_APP_PREFERENCES_PREPROC_RUN_PRESENT_BGCOLOR = "run.present.bgcolor";
+// public static final String PROCESSING_APP_PREFERENCES_PREPROC_EXPORT_APPLICATION_STOP = "export.application.stop";
+// public static final String PROCESSING_APP_PREFERENCES_PREPROC_RUN_PRESENT_STOP_COLOR = "run.present.stop.color";
+// public static final String PROCESSING_APP_PREFERENCES_PREPROC_RUN_WINDOW_BGCOLOR = "run.window.bgcolor";
+// public static final String PROCESSING_APP_PREFERENCES_PREPROC_PREPROC_IMPORTS_LIST = "preproc.imports.list";
+
+}
diff --git a/editor/org.processing.editor/src/org/processing/preferences/PreferenceInitializer.java b/editor/org.processing.editor/src/org/processing/preferences/PreferenceInitializer.java
new file mode 100644
index 000000000..2533609f5
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/preferences/PreferenceInitializer.java
@@ -0,0 +1,38 @@
+package org.processing.preferences;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+import org.processing.editor.ProcessingEditorPlugin;
+
+/**
+ * Class used to initialize default preference values.
+ */
+public class PreferenceInitializer extends AbstractPreferenceInitializer {
+
+ /**
+ * Sets the default preference values
+ */
+ public void initializeDefaultPreferences() {
+ IPreferenceStore store = ProcessingEditorPlugin.getDefault().getPreferenceStore();
+
+ //store.setDefault(PreferenceContants.PROCESSING_SKETCH, value);
+ store.setDefault(PreferenceConstants.PROCESSING_AUTO_INDENT, true);
+
+ // PROCESSING_PREFERENCES are processing.app preferences
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_EDITOR_TABS_SIZE, "4");
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_PREPROC_SUBSTITUTE_FLOATS, "true");
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_PREPROC_WEB_COLORS, "true");
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_PREPROC_COLOR_DATATYPE, "true");
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_PREPROC_ENHANCED_CASTING, "true");
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_PREPROC_SUBSTITUTE_UNICODE, "true");
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_PREPROC_OUTPUT_PARSE_TREE, "false");
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_PREPROC_EXPORT_APPLICATION_FULLSCREEN, "false");
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_PREPROC_RUN_PRESENT_BGCOLOR, "#666666");
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_PREPROC_EXPORT_APPLICATION_STOP, "true");
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_PREPROC_RUN_PRESENT_STOP_COLOR, "#cccccc");
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_PREPROC_RUN_WINDOW_BGCOLOR, "#ECE9D8");
+// store.setDefault(PreferenceConstants.PROCESSING_APP_PREFERENCES_PREPROC_PREPROC_IMPORTS_LIST, "java.applet.*,java.awt.Dimension,java.awt.Frame,java.awt.event.MouseEvent,java.awt.event.KeyEvent,java.awt.event.FocusEvent,java.awt.Image,java.io.*,java.net.*,java.text.*,java.util.*,java.util.zip.*,java.util.regex.*");
+ }
+
+}
diff --git a/editor/org.processing.editor/src/org/processing/preferences/ProcessingPreferencesPage.java b/editor/org.processing.editor/src/org/processing/preferences/ProcessingPreferencesPage.java
new file mode 100644
index 000000000..8ad2ade58
--- /dev/null
+++ b/editor/org.processing.editor/src/org/processing/preferences/ProcessingPreferencesPage.java
@@ -0,0 +1,70 @@
+package org.processing.preferences;
+
+import org.eclipse.jface.preference.*;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.IWorkbench;
+import org.processing.editor.ProcessingEditorPlugin;
+
+/**
+ * This page is used to modify preferences only. They
+ * are stored in the preference store that belongs to
+ * the main plug-in class. That way, preferences can
+ * be accessed directly via the preference store.
+ *