diff --git a/pdex/.project b/pdex/.project index 1be6ebc0c..dd2d29121 100644 --- a/pdex/.project +++ b/pdex/.project @@ -10,6 +10,16 @@ + + org.eclipse.ui.externaltools.ExternalToolBuilder + full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/processing-experimental build.xml [Builder] (1).launch + + + org.eclipse.jdt.core.javanature diff --git a/pdex/build.xml b/pdex/build.xml index 2e0f18baa..489c3f93d 100644 --- a/pdex/build.xml +++ b/pdex/build.xml @@ -56,4 +56,10 @@ + + + + + + diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java new file mode 100644 index 000000000..03841481e --- /dev/null +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -0,0 +1,1509 @@ +package processing.mode.experimental; + +import java.awt.Rectangle; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTree; +import javax.swing.SwingWorker; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.table.DefaultTableModel; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; +import org.eclipse.jdt.core.dom.ArrayAccess; +import org.eclipse.jdt.core.dom.ArrayCreation; +import org.eclipse.jdt.core.dom.ArrayInitializer; +import org.eclipse.jdt.core.dom.ArrayType; +import org.eclipse.jdt.core.dom.Assignment; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.BodyDeclaration; +import org.eclipse.jdt.core.dom.BooleanLiteral; +import org.eclipse.jdt.core.dom.BreakStatement; +import org.eclipse.jdt.core.dom.CastExpression; +import org.eclipse.jdt.core.dom.CatchClause; +import org.eclipse.jdt.core.dom.CharacterLiteral; +import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; +import org.eclipse.jdt.core.dom.ClassInstanceCreation; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ConditionalExpression; +import org.eclipse.jdt.core.dom.ConstructorInvocation; +import org.eclipse.jdt.core.dom.ContinueStatement; +import org.eclipse.jdt.core.dom.DoStatement; +import org.eclipse.jdt.core.dom.EnhancedForStatement; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.FieldAccess; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.ForStatement; +import org.eclipse.jdt.core.dom.IfStatement; +import org.eclipse.jdt.core.dom.InfixExpression; +import org.eclipse.jdt.core.dom.Initializer; +import org.eclipse.jdt.core.dom.InstanceofExpression; +import org.eclipse.jdt.core.dom.Javadoc; +import org.eclipse.jdt.core.dom.LineComment; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.Name; +import org.eclipse.jdt.core.dom.NodeFinder; +import org.eclipse.jdt.core.dom.NumberLiteral; +import org.eclipse.jdt.core.dom.ParameterizedType; +import org.eclipse.jdt.core.dom.ParenthesizedExpression; +import org.eclipse.jdt.core.dom.PostfixExpression; +import org.eclipse.jdt.core.dom.PrefixExpression; +import org.eclipse.jdt.core.dom.PrimitiveType; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.ReturnStatement; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SimpleType; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.Statement; +import org.eclipse.jdt.core.dom.StringLiteral; +import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; +import org.eclipse.jdt.core.dom.SuperConstructorInvocation; +import org.eclipse.jdt.core.dom.SuperFieldAccess; +import org.eclipse.jdt.core.dom.SuperMethodInvocation; +import org.eclipse.jdt.core.dom.SwitchCase; +import org.eclipse.jdt.core.dom.SwitchStatement; +import org.eclipse.jdt.core.dom.SynchronizedStatement; +import org.eclipse.jdt.core.dom.ThrowStatement; +import org.eclipse.jdt.core.dom.TryStatement; +import org.eclipse.jdt.core.dom.Type; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclarationStatement; +import org.eclipse.jdt.core.dom.VariableDeclarationExpression; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.core.dom.WhileStatement; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; + + +import processing.app.Base; +import processing.app.SketchCode; +import processing.app.syntax.InputHandler.clipboard_copy; + +public class ASTGenerator { + + protected ErrorCheckerService errorCheckerService; + + protected DebugEditor editor; + + public DefaultMutableTreeNode codeTree = new DefaultMutableTreeNode(); + + private DefaultMutableTreeNode currentParent = null; + + private JFrame frame2, frameAutoComp; + + private JTree jtree; + + private CompilationUnit compilationUnit; + + private JTable tableAuto; + + public ASTGenerator(ErrorCheckerService ecs) { + this.errorCheckerService = ecs; + this.editor = ecs.getEditor(); + frame2 = new JFrame(); + + jtree = new JTree(); + frame2.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame2.setBounds(new Rectangle(100, 100, 460, 620)); + JScrollPane sp = new JScrollPane(); + sp.setViewportView(jtree); + frame2.add(sp); + + frameAutoComp = new JFrame(); + frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); + tableAuto = new JTable(); + JScrollPane sp2 = new JScrollPane(); + sp2.setViewportView(tableAuto); + frameAutoComp.add(sp2); + + } + + public class ASTNodeWrapper { + private ASTNode node; + + private String label; + + private int lineNumber; + + private int apiLevel; + + public ASTNodeWrapper(ASTNode node) { + if (node == null) + return; + this.node = node; + label = getNodeAsString(node); + if (label == null) + label = node.toString(); + lineNumber = compilationUnit.getLineNumber(node.getStartPosition()); + label += " | Line " + lineNumber; + apiLevel = 0; + } + + public String toString() { + return label; + } + + public ASTNode getNode() { + return node; + } + + public String getLabel() { + return label; + } + + public int getNodeType() { + return node.getNodeType(); + } + + public int getLineNumber() { + return lineNumber; + } + } + + private DefaultMutableTreeNode buildAST2(String source) { + ASTParser parser = ASTParser.newParser(AST.JLS4); + parser.setSource(source.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + + Map options = JavaCore.getOptions(); + + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + parser.setCompilerOptions(options); + compilationUnit = (CompilationUnit) parser.createAST(null); +// OutlineVisitor visitor = new OutlineVisitor(); +// compilationUnit.accept(visitor); + codeTree = new DefaultMutableTreeNode( + getNodeAsString((ASTNode) compilationUnit + .types().get(0))); + visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if (codeTree != null) { +// if (jtree.hasFocus() || frame2.hasFocus()) +// return; + jtree.setModel(new DefaultTreeModel(codeTree)); + ((DefaultTreeModel) jtree.getModel()).reload(); + if (!frame2.isVisible()) + frame2.setVisible(true); + if (!frameAutoComp.isVisible()) + frameAutoComp.setVisible(true); + jtree.validate(); + } + } + }; + worker.execute(); + + return codeTree; + } + + public DefaultMutableTreeNode buildAST() { + return buildAST2(errorCheckerService.sourceCode); + } + + public String[] checkForTypes2(ASTNode node) { + + List vdfs = null; + switch (node.getNodeType()) { + case ASTNode.TYPE_DECLARATION: + return new String[] { ((TypeDeclaration) node).getName().toString() }; + + case ASTNode.METHOD_DECLARATION: + String[] ret1 = new String[] { ((MethodDeclaration) node).getName() + .toString() }; + return ret1; + + case ASTNode.SINGLE_VARIABLE_DECLARATION: + return new String[] { ((SingleVariableDeclaration) node).getName() + .toString() }; + + case ASTNode.FIELD_DECLARATION: + vdfs = ((FieldDeclaration) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + vdfs = ((VariableDeclarationStatement) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + vdfs = ((VariableDeclarationExpression) node).fragments(); + break; + default: + break; + } + + if (vdfs != null) { + String ret[] = new String[vdfs.size()]; + int i = 0; + for (VariableDeclarationFragment vdf : vdfs) { + ret[i++] = vdf.getName().toString(); + } + return ret; + } + + return null; + } + + public static String[] checkForTypes(ASTNode node) { + + List vdfs = null; + switch (node.getNodeType()) { + case ASTNode.TYPE_DECLARATION: + return new String[] { getNodeAsString(node) }; + + case ASTNode.METHOD_DECLARATION: + String[] ret1 = new String[] { getNodeAsString(node) }; + return ret1; + + case ASTNode.SINGLE_VARIABLE_DECLARATION: + return new String[] { getNodeAsString(node) }; + + case ASTNode.FIELD_DECLARATION: + vdfs = ((FieldDeclaration) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + vdfs = ((VariableDeclarationStatement) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + vdfs = ((VariableDeclarationExpression) node).fragments(); + break; + default: + break; + } + + if (vdfs != null) { + String ret[] = new String[vdfs.size()]; + int i = 0; + for (VariableDeclarationFragment vdf : vdfs) { + ret[i++] = getNodeAsString(vdf); + } + return ret; + } + + return null; + } + + @SuppressWarnings("unchecked") + public ArrayList getNameIfType(ASTNode astnode) { + + ArrayList names = new ArrayList(); + List sprops = astnode + .structuralPropertiesForType(); + for (StructuralPropertyDescriptor sprop : sprops) { + ASTNode cnode = null; + if (!sprop.isChildListProperty()) { + if (astnode.getStructuralProperty(sprop) instanceof ASTNode) { + cnode = (ASTNode) astnode.getStructuralProperty(sprop); + //if(cnode) + } + } else { + // Childlist prop + List nodelist = (List) astnode + .getStructuralProperty(sprop); + for (ASTNode clnode : nodelist) { + + } + } + } + + return names; + } + + public static ASTNode resolveExpression(ASTNode nearestNode, + ASTNode expression) { +// ASTNode anode = null; + if (expression instanceof SimpleName) { + return findDeclaration2(((SimpleName) expression), nearestNode); + } else if (expression instanceof MethodInvocation) { + return findDeclaration2(((MethodInvocation) expression).getName(), + nearestNode); + } else if (expression instanceof FieldAccess) { + return findDeclaration2(((FieldAccess) expression).getName(), nearestNode); + } else if (expression instanceof QualifiedName) { + return findDeclaration2(((QualifiedName) expression).getName(), + nearestNode); + } + +// if (anode != null) { +// System.out.println("Expression: " + anode); +// anode = resolveExpression(nearestNode, anode); +// } +// String word = anode.toString(); +// // Here expression should be a SN type hopefully. +// System.out.println("Final Expression: " + word); +//// anode = expression.getParent(); +// +// anode = nearestNode.getParent(); +// ASTNode matchinNode = null; +// while (anode != null) { +// +// List sprops = anode +// .structuralPropertiesForType(); +// for (StructuralPropertyDescriptor sprop : sprops) { +// ASTNode cnode = null; +// if (!sprop.isChildListProperty()) { +// if (anode.getStructuralProperty(sprop) instanceof ASTNode) { +// cnode = (ASTNode) anode.getStructuralProperty(sprop); +// String[] types = checkForTypes(cnode); +// if (types != null) { +// for (int i = 0; i < types.length; i++) { +// if (types[i].startsWith(word)) +// { +// System.out.println("match: "+types[i]); +// } +// } +// } +// } +// } else { +// // Childlist prop +// List nodelist = (List) anode +// .getStructuralProperty(sprop); +// for (ASTNode clnode : nodelist) { +// String[] types = checkForTypes(clnode); +// if (types != null) { +// for (int i = 0; i < types.length; i++) { +// if (types[i].startsWith(word)) +// System.out.println("match: "+types[i]);; +// } +// } +// } +// } +// } +// anode = anode.getParent(); +// } + + return null; + } + + public static TypeDeclaration getDefiningNode(ASTNode node) { + ASTNode parent = node.getParent(); + while (!(parent instanceof TypeDeclaration)) { + parent = parent.getParent(); + if (parent instanceof CompilationUnit) + return null; + } + return (TypeDeclaration) parent; + } + + public void updatePredictions(final String word, final int line) { + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { +// ArrayList candidates = new ArrayList(); + + //ASTNodeWrapper[][] candi = new ASTNodeWrapper[80][1]; + int lineNumber = line; + // Adjust line number for tabbed sketches + if (errorCheckerService != null) { + editor = errorCheckerService.getEditor(); + int codeIndex = editor.getSketch().getCodeIndex(editor + .getCurrentTab()); + if (codeIndex > 0) + for (int i = 0; i < codeIndex; i++) { + SketchCode sc = editor.getSketch().getCode(i); + int len = Base.countLines(sc.getProgram()) + 1; + lineNumber += len; + } + + } + + ASTNode anode = null; + ASTParser parser = ASTParser.newParser(AST.JLS4); + parser.setKind(ASTParser.K_EXPRESSION); + parser.setSource(word.toCharArray()); + ASTNode testnode = parser.createAST(null); + System.out.print("Typed: " + word + "|"); + anode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() + .get(0)); + System.out.println(lineNumber + " Nearest ASTNode to PRED " + + getNodeAsString(anode)); + + ArrayList candidates = new ArrayList(); + + if (testnode instanceof SimpleName) { + anode = anode.getParent(); + while (anode != null) { + + List sprops = anode + .structuralPropertiesForType(); + for (StructuralPropertyDescriptor sprop : sprops) { + ASTNode cnode = null; + if (!sprop.isChildListProperty()) { + if (anode.getStructuralProperty(sprop) instanceof ASTNode) { + cnode = (ASTNode) anode.getStructuralProperty(sprop); + String[] types = checkForTypes(cnode); + if (types != null) { + for (int i = 0; i < types.length; i++) { + if (types[i].startsWith(word)) + candidates.add(types[i]); + } + } + } + } else { + // Childlist prop + List nodelist = (List) anode + .getStructuralProperty(sprop); + for (ASTNode clnode : nodelist) { + String[] types = checkForTypes(clnode); + if (types != null) { + for (int i = 0; i < types.length; i++) { + if (types[i].startsWith(word)) + candidates.add(types[i]); + } + } + } + } + } + anode = anode.getParent(); + } + } else { + + // Complicated completion + System.out.println("Not a SN " + getNodeAsString(testnode)); + ASTNode det = resolveExpression(anode, testnode); + if (det != null) { + TypeDeclaration td = null; + if (det instanceof MethodDeclaration) { + if (((MethodDeclaration) det).getReturnType2() instanceof SimpleType) { + SimpleType stp = (SimpleType) (((MethodDeclaration) det) + .getReturnType2()); + td = (TypeDeclaration) findDeclaration(stp.getName()); + } + } else if (det instanceof FieldDeclaration) { + if (((FieldDeclaration) det).getType() instanceof SimpleType) { + SimpleType stp = (SimpleType) (((FieldDeclaration) det) + .getType()); + td = (TypeDeclaration) findDeclaration(stp.getName()); + } + } + + System.out.println(getNodeAsString(det) + " defined in " + + getNodeAsString(td)); + if (td != null) { + for (int i = 0; i < td.getFields().length; i++) { + candidates.add(getNodeAsString(td.getFields()[i])); + } + for (int i = 0; i < td.getMethods().length; i++) { + candidates.add(getNodeAsString(td.getMethods()[i])); + } + } + + } + + } + + String[][] candi = new String[candidates.size()][1]; + for (int i = 0; i < candi.length; i++) { + candi[i][0] = candidates.get(i); + } + System.out.println("K = " + candidates.size()); + DefaultTableModel tm = new DefaultTableModel( + candi, + new String[] { "Suggestions" }); + tableAuto.setModel(tm); + tableAuto.validate(); + tableAuto.repaint(); + } + }; + + worker.execute(); + + } + + @SuppressWarnings("unchecked") + private static ASTNode findClosestParentNode(int lineNumber, ASTNode node) { + Iterator it = node + .structuralPropertiesForType().iterator(); + //System.err.println("Props of " + node.getClass().getName()); + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { +// System.out +// .println(node.getStructuralProperty(prop) + " -> " + (prop)); + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); + System.out.println("Looking at " + getNodeAsString(cnode)); + int cLineNum = ((CompilationUnit) cnode.getRoot()) + .getLineNumber(cnode.getStartPosition() + cnode.getLength()); + if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { + return findClosestParentNode(lineNumber, cnode); + } + } + } + } + + else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + int cLineNum = ((CompilationUnit) cnode.getRoot()) + .getLineNumber(cnode.getStartPosition() + cnode.getLength()); + System.out.println("Looking at " + getNodeAsString(cnode)); + if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { + return findClosestParentNode(lineNumber, cnode); + } + } + } + } + return node; + } + + @SuppressWarnings("unchecked") + private static ASTNode findClosestNode(int lineNumber, ASTNode node) { + ASTNode parent = findClosestParentNode(lineNumber, node); + if (parent == null) + return null; + if (getLineNumber(parent) == lineNumber) + return parent; + List nodes = null; + if (parent instanceof TypeDeclaration) { + nodes = (List) ((TypeDeclaration) parent) + .getStructuralProperty(TypeDeclaration.BODY_DECLARATIONS_PROPERTY); + } else if (parent instanceof Block) { + nodes = (List) ((Block) parent) + .getStructuralProperty(Block.STATEMENTS_PROPERTY); + } else { + System.err.println("THIS CONDITION SHOULD NOT OCCUR - findClosestNode " + + getNodeAsString(parent)); + return null; + } + + ASTNode retNode = nodes.get(0); + for (ASTNode cNode : nodes) { + if (getLineNumber(cNode) <= lineNumber) + retNode = cNode; + else + break; + } + + return retNode; + } + +// static DefaultMutableTreeNode findNodeBS(DefaultMutableTreeNode tree, +// int lineNumber, String name, +// int elementOffset) { +// if (tree.getUserObject() == null) +// return null; +// +// ASTNodeWrapper node = ((ASTNodeWrapper) tree.getUserObject()); +// +// if (node.getLineNumber() == lineNumber) { +// System.out.println("Located line " + lineNumber + " , " + tree); +// if (name == null) +// return tree; +// else +// return findOnLine(tree, lineNumber, name, elementOffset, node.getNode() +// .getStartPosition()); +// } +// +// int low = 0, high = tree.getChildCount() - 1, mid = (high + low) / 2; +// DefaultMutableTreeNode tnode = null; +// while (low <= high) { +// mid = (high + low) / 2; +// tnode = (DefaultMutableTreeNode) tree.getChildAt(mid); +// node = ((ASTNodeWrapper) tnode.getUserObject()); +// if (node.getLineNumber() == lineNumber) { +// System.out.println("Located line " + lineNumber + " , " + tnode); +// if (name == null) +// return tnode; +// else +// return findOnLine(tnode, lineNumber, name, elementOffset, node +// .getNode().getStartPosition()); +// } else if (lineNumber < node.getLineNumber()) { +// high = mid - 1; +// } else { +// if (high - mid <= 1) { +// if (lineNumber > ((ASTNodeWrapper) ((DefaultMutableTreeNode) tree +// .getChildAt(high)).getUserObject()).getLineNumber()) //high l no. +// low = mid + 1; +// else +// +// high = mid - 1; +// } +// low = mid + 1; +// } +// +// } +// +// if (!tnode.isLeaf()) +// return findNodeBS(tnode, lineNumber, name, elementOffset); +// else +// return tnode; +// +// //System.out.println("visiting: " + getNodeAsString(node.getNode()) + " on line "+node.getLineNumber()); +// if (node.getLineNumber() == lineNumber) { +// System.err.println("Located line: " + node.toString()); +// if (name == null) // name ==null, finds any node equal to line +// // number +// { +// System.out.println("Closest node at line: " + lineNumber); +// return tree; +// } else +// return findOnLine(tree, lineNumber, name, elementOffset, node.getNode() +// .getStartPosition()); +// +// } else if (!tree.isLeaf()) { +// for (int i = 0; i < tree.getChildCount(); i++) { +// .getChildAt(i), +// lineNumber, name, elementOffset); +// if (node2 != null) +// return node2; +// } +// } +// +// return null; +// } + + public DefaultMutableTreeNode getAST() { + return codeTree; + } + + public String getLabelForASTNode(int lineNumber, String name, int offset) { + retLabelString = ""; + getASTNodeAt(lineNumber, name, offset, false); + return retLabelString; + } + + public void scrollToDeclaration(int lineNumber, String name, int offset) { + getASTNodeAt(lineNumber, name, offset, true); + } + + String retLabelString; + + public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, + boolean scrollOnly) { + System.out.println("--------"); + if (errorCheckerService != null) { + editor = errorCheckerService.getEditor(); + int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); + if (codeIndex > 0) { + for (int i = 0; i < codeIndex; i++) { + SketchCode sc = editor.getSketch().getCode(i); + int len = Base.countLines(sc.getProgram()) + 1; + lineNumber += len; + } + } + + } + System.out.println("FLON: " + lineNumber); + ASTNode lineNode = findLineOfNode(compilationUnit, lineNumber, offset, name); + System.out.println("+> " + lineNode); + ASTNode decl = null; + if (lineNode != null) { + System.out.println("FLON2: " + lineNumber + " LN O " + + lineNode.getStartPosition()); + ASTNode simpName = pinpointOnLine(lineNode, offset, + lineNode.getStartPosition(), name); + System.out.println("+++> " + simpName); + if (simpName instanceof SimpleName) { + System.out.println(getNodeAsString(simpName)); + decl = findDeclaration((SimpleName) simpName); + if (decl != null) { + System.err.println("DECLA: " + decl.getClass().getName()); + retLabelString = getNodeAsString(decl); + } else + System.err.println("null"); + + System.out.println(getNodeAsString(decl)); + } + } + +// +// retStr = ""; + if (decl != null && scrollOnly) { + System.err.println("FINAL String label: " + getNodeAsString(decl)); + + DefaultProblem dpr = new DefaultProblem(null, null, -1, null, -1, + decl.getStartPosition(), + decl.getStartPosition(), + getLineNumber(decl) + 1, 0); + int[] position = errorCheckerService.calculateTabIndexAndLineNumber(dpr); + System.out.println("Tab " + position[0] + ", Line: " + (position[1])); + Problem p = new Problem(dpr, position[0], position[1]); + //errorCheckerService.scrollToErrorLine(p); + } // uncomment this one, it works + + return null; + } + + private static int getLineNumber(ASTNode node) { + return ((CompilationUnit) node.getRoot()).getLineNumber(node + .getStartPosition()); + } + + public static void main(String[] args) { + traversal2(); +// ASTParserd + } + + public static void traversal2() { + ASTParser parser = ASTParser.newParser(AST.JLS4); + String source = readFile("/media/quarkninja/Work/TestStuff/low.java"); +// String source = "package decl; \npublic class ABC{\n int ret(){\n}\n}"; + parser.setSource(source.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + + Map options = JavaCore.getOptions(); + + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + parser.setCompilerOptions(options); + + CompilationUnit cu = (CompilationUnit) parser.createAST(null); + System.out.println(CompilationUnit.propertyDescriptors(AST.JLS4).size()); + + DefaultMutableTreeNode astTree = new DefaultMutableTreeNode( + "CompilationUnit"); + System.err.println("Errors: " + cu.getProblems().length); + visitRecur(cu, astTree); + System.out.println(astTree.getChildCount()); + + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + JFrame frame2 = new JFrame(); + JTree jtree = new JTree(astTree); + frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame2.setBounds(new Rectangle(100, 100, 460, 620)); + JScrollPane sp = new JScrollPane(); + sp.setViewportView(jtree); + frame2.add(sp); + frame2.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + + ASTNode found = NodeFinder.perform(cu, 468, 5); + if (found != null) { + System.out.println(found); + } + } + + @SuppressWarnings({ "unchecked" }) + public static void visitRecur(ASTNode node, DefaultMutableTreeNode tnode) { + Iterator it = node + .structuralPropertiesForType().iterator(); + //System.err.println("Props of " + node.getClass().getName()); + DefaultMutableTreeNode ctnode = null; + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { +// System.out +// .println(node.getStructuralProperty(prop) + " -> " + (prop)); + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); + if (isAddableASTNode(cnode)) { + ctnode = new DefaultMutableTreeNode( + getNodeAsString((ASTNode) node + .getStructuralProperty(prop))); + tnode.add(ctnode); + visitRecur(cnode, ctnode); + } + } else { + tnode.add(new DefaultMutableTreeNode(node + .getStructuralProperty(prop))); + } + } + } + + else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + if (isAddableASTNode(cnode)) { + ctnode = new DefaultMutableTreeNode(getNodeAsString(cnode)); + tnode.add(ctnode); + visitRecur(cnode, ctnode); + } else + visitRecur(cnode, tnode); + } + } + } + } + + public static void printRecur(ASTNode node) { + Iterator it = node + .structuralPropertiesForType().iterator(); + //System.err.println("Props of " + node.getClass().getName()); + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { +// System.out +// .println(node.getStructuralProperty(prop) + " -> " + (prop)); + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); + System.out.println(getNodeAsString(cnode)); + printRecur(cnode); + } + } + } + + else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + System.out.println(getNodeAsString(cnode)); + printRecur(cnode); + } + } + } + } + + @SuppressWarnings("unchecked") + private static ASTNode findLineOfNode(ASTNode node, int lineNumber, + int offset, String name) { + + CompilationUnit root = (CompilationUnit) node.getRoot(); +// System.out.println("Inside "+getNodeAsString(node) + " | " + root.getLineNumber(node.getStartPosition())); + if (root.getLineNumber(node.getStartPosition()) == lineNumber) { + System.err + .println(3 + getNodeAsString(node) + " len " + node.getLength()); + + if (offset < node.getLength()) + return node; + else { + System.err.println(-11); + return null; + } + } + for (Object oprop : node.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode retNode = findLineOfNode((ASTNode) node + .getStructuralProperty(prop), + lineNumber, offset, name); + if (retNode != null) { +// System.err.println(11 + getNodeAsString(retNode)); + return retNode; + } + } + } + } else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + + ASTNode rr = findLineOfNode(retNode, lineNumber, offset, name); + if (rr != null) { +// System.err.println(12 + getNodeAsString(rr)); + return rr; + } + } + } + } +// System.err.println("-1"); + return null; + } + + /** + * + * @param node + * @param offset + * - from textarea painter + * @param lineStartOffset + * - obtained from findLineOfNode + * @param name + * @param root + * @return + */ + @SuppressWarnings("unchecked") + public static ASTNode pinpointOnLine(ASTNode node, int offset, + int lineStartOffset, String name) { + + if (node instanceof SimpleName) { + SimpleName sn = (SimpleName) node; + if ((lineStartOffset + offset) >= sn.getStartPosition() + && (lineStartOffset + offset) <= sn.getStartPosition() + + sn.getLength()) { + if (sn.toString().equals(name)) + return sn; + else + return null; + } else + return null; + } + for (Object oprop : node.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode retNode = pinpointOnLine((ASTNode) node + .getStructuralProperty(prop), + offset, lineStartOffset, name); + if (retNode != null) { +// System.err.println(11 + getNodeAsString(retNode)); + return retNode; + } + } + } + } else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + + ASTNode rr = pinpointOnLine(retNode, offset, lineStartOffset, name); + if (rr != null) { +// System.err.println(12 + getNodeAsString(rr)); + return rr; + } + } + } + } +// System.err.println("-1"); + return null; + } + + @SuppressWarnings("unchecked") + private static ASTNode findDeclaration(Name findMe) { + ASTNode declaringClass = null; + ASTNode parent = findMe.getParent(); + ASTNode ret = null; + ArrayList constrains = new ArrayList(); + if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) { + Expression exp = (Expression) ((MethodInvocation) parent) + .getStructuralProperty(MethodInvocation.EXPRESSION_PROPERTY); + //TODO: Note the imbalance of constrains.add(ASTNode.METHOD_DECLARATION); + // Possibly a bug here. Investigate later. + if (((MethodInvocation) parent).getName().toString() + .equals(findMe.toString())) { + constrains.add(ASTNode.METHOD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("MI EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) + .getName())); + if (stp == null) + return null; + declaringClass = findDeclaration(stp.getName()); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) + .getName())); + if (stp == null) + return null; + declaringClass = findDeclaration((stp.getName())); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); + if (stp == null) + return null; + declaringClass = findDeclaration(stp.getName()); + System.out.println("MI.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } + + } + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + } + } else if (parent.getNodeType() == ASTNode.FIELD_ACCESS) { + FieldAccess fa = (FieldAccess) parent; + Expression exp = fa.getExpression(); + if (fa.getName().toString().equals(findMe.toString())) { + constrains.add(ASTNode.FIELD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("FA EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) + .getName())); + if (stp == null) + return null; + declaringClass = findDeclaration(stp.getName()); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) + .getName())); + if (stp == null) + return null; + declaringClass = findDeclaration((stp.getName())); + constrains.add(ASTNode.TYPE_DECLARATION); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); + if (stp == null) + return null; + declaringClass = findDeclaration(stp.getName()); + System.out.println("FA.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } + } + + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + } + } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) { + + QualifiedName qn = (QualifiedName) parent; + if (!findMe.toString().equals(qn.getQualifier().toString())) { + + SimpleType stp = extracTypeInfo(findDeclaration((qn.getQualifier()))); + declaringClass = findDeclaration(stp.getName()); + System.out.println(qn.getQualifier() + "->" + qn.getName()); + System.out.println("QN decl class: " + getNodeAsString(declaringClass)); + constrains.clear(); + constrains.add(ASTNode.TYPE_DECLARATION); + constrains.add(ASTNode.FIELD_DECLARATION); + return definedIn(declaringClass, qn.getName().toString(), constrains, + null); + } + } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { + constrains.add(ASTNode.TYPE_DECLARATION); + if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) + constrains.add(ASTNode.CLASS_INSTANCE_CREATION); + } else if (parent instanceof Expression) { +// constrains.add(ASTNode.TYPE_DECLARATION); +// constrains.add(ASTNode.METHOD_DECLARATION); +// constrains.add(ASTNode.FIELD_DECLARATION); + } + while (parent != null) { + System.out.println("findDeclaration1 -> " + getNodeAsString(parent)); + for (Object oprop : parent.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (parent.getStructuralProperty(prop) instanceof ASTNode) { + System.out.println(prop + " C/S Prop of -> " + + getNodeAsString(parent)); + ret = definedIn((ASTNode) parent.getStructuralProperty(prop), + findMe.toString(), constrains, declaringClass); + if (ret != null) + return ret; + } + } else if (prop.isChildListProperty()) { + System.out.println((prop) + " ChildList props of " + + getNodeAsString(parent)); + List nodelist = (List) parent + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + ret = definedIn(retNode, findMe.toString(), constrains, + declaringClass); + if (ret != null) + return ret; + } + } + } + parent = parent.getParent(); + } + return null; + } + + private static ASTNode findDeclaration2(Name findMe, ASTNode alternateParent) { + ASTNode declaringClass = null; + ASTNode parent = findMe.getParent(); + ASTNode ret = null; + ArrayList constrains = new ArrayList(); + if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) { + Expression exp = (Expression) ((MethodInvocation) parent) + .getStructuralProperty(MethodInvocation.EXPRESSION_PROPERTY); + //TODO: Note the imbalance of constrains.add(ASTNode.METHOD_DECLARATION); + // Possibly a bug here. Investigate later. + if (((MethodInvocation) parent).getName().toString() + .equals(findMe.toString())) { + constrains.add(ASTNode.METHOD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("MI EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp) + .getName(), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2(stp.getName(), alternateParent); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration2(((FieldAccess) exp) + .getName(), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2((stp.getName()), alternateParent); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration2(((SimpleName) exp), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2(stp.getName(), alternateParent); + System.out.println("MI.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } + + } + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + alternateParent = alternateParent.getParent(); + } + } else if (parent.getNodeType() == ASTNode.FIELD_ACCESS) { + FieldAccess fa = (FieldAccess) parent; + Expression exp = fa.getExpression(); + if (fa.getName().toString().equals(findMe.toString())) { + constrains.add(ASTNode.FIELD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("FA EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp) + .getName(), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2(stp.getName(), alternateParent); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration2(((FieldAccess) exp) + .getName(), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2((stp.getName()), alternateParent); + constrains.add(ASTNode.TYPE_DECLARATION); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration2(((SimpleName) exp), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2(stp.getName(), alternateParent); + System.out.println("FA.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } + } + + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + alternateParent = alternateParent.getParent(); + } + } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) { + + QualifiedName qn = (QualifiedName) parent; + if (!findMe.toString().equals(qn.getQualifier().toString())) { + + SimpleType stp = extracTypeInfo(findDeclaration2((qn.getQualifier()), + alternateParent)); + declaringClass = findDeclaration2(stp.getName(), alternateParent); + System.out.println(qn.getQualifier() + "->" + qn.getName()); + System.out.println("QN decl class: " + getNodeAsString(declaringClass)); + constrains.clear(); + constrains.add(ASTNode.TYPE_DECLARATION); + constrains.add(ASTNode.FIELD_DECLARATION); + return definedIn(declaringClass, qn.getName().toString(), constrains, + null); + } + } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { + constrains.add(ASTNode.TYPE_DECLARATION); + if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) + constrains.add(ASTNode.CLASS_INSTANCE_CREATION); + } else if (parent instanceof Expression) { +// constrains.add(ASTNode.TYPE_DECLARATION); +// constrains.add(ASTNode.METHOD_DECLARATION); +// constrains.add(ASTNode.FIELD_DECLARATION); + } + System.out.println("Alternate parent: " + getNodeAsString(alternateParent)); + while (alternateParent != null) { + System.out.println("findDeclaration2 -> " + + getNodeAsString(alternateParent)); + for (Object oprop : alternateParent.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (alternateParent.getStructuralProperty(prop) instanceof ASTNode) { + System.out.println(prop + " C/S Prop of -> " + + getNodeAsString(alternateParent)); + ret = definedIn((ASTNode) alternateParent + .getStructuralProperty(prop), + findMe.toString(), constrains, declaringClass); + if (ret != null) + return ret; + } + } else if (prop.isChildListProperty()) { + System.out.println((prop) + " ChildList props of " + + getNodeAsString(alternateParent)); + List nodelist = (List) alternateParent + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + ret = definedIn(retNode, findMe.toString(), constrains, + declaringClass); + if (ret != null) + return ret; + } + } + } + alternateParent = alternateParent.getParent(); + } + return null; + } + + /** + * Find the SimpleType from FD, SVD, VDS, etc + * + * @param node + * @return + */ + private static SimpleType extracTypeInfo(ASTNode node) { + if (node == null) + return null; + switch (node.getNodeType()) { + case ASTNode.METHOD_DECLARATION: + return (SimpleType) ((MethodDeclaration) node) + .getStructuralProperty(MethodDeclaration.RETURN_TYPE2_PROPERTY); + case ASTNode.FIELD_DECLARATION: + return (SimpleType) ((FieldDeclaration) node) + .getStructuralProperty(FieldDeclaration.TYPE_PROPERTY); + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + return (SimpleType) ((VariableDeclarationExpression) node) + .getStructuralProperty(VariableDeclarationExpression.TYPE_PROPERTY); + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + return (SimpleType) ((VariableDeclarationStatement) node) + .getStructuralProperty(VariableDeclarationStatement.TYPE_PROPERTY); + case ASTNode.SINGLE_VARIABLE_DECLARATION: + return (SimpleType) ((SingleVariableDeclaration) node) + .getStructuralProperty(SingleVariableDeclaration.TYPE_PROPERTY); + } + return null; + } + + @SuppressWarnings("unchecked") + private static ASTNode definedIn(ASTNode node, String name, + ArrayList constrains, + ASTNode declaringClass) { + if (node == null) + return null; + if (constrains != null) { + System.out.println("Looking at " + getNodeAsString(node) + " for " + name + + " in definedIn"); + if (!constrains.contains(node.getNodeType()) && constrains.size() > 0) { + System.err.print("definedIn -1 " + " But constrain was "); + for (Integer integer : constrains) { + System.out.print(ASTNode.nodeClassForType(integer) + ","); + } + System.out.println(); + return null; + } + } + + List vdfList = null; + switch (node.getNodeType()) { + + case ASTNode.TYPE_DECLARATION: + System.err.println(getNodeAsString(node)); + TypeDeclaration td = (TypeDeclaration) node; + if (td.getName().toString().equals(name)) { + if (constrains.contains(ASTNode.CLASS_INSTANCE_CREATION)) { + // look for constructor; + MethodDeclaration[] methods = td.getMethods(); + for (MethodDeclaration md : methods) { + if (md.getName().toString().equals(name)) { + return md; + } + } + } else { + // it's just the TD we're lookin for + return node; + } + } else { + if (constrains.contains(ASTNode.FIELD_DECLARATION)) { + // look for fields + FieldDeclaration[] fields = td.getFields(); + for (FieldDeclaration fd : fields) { + List fragments = fd.fragments(); + for (VariableDeclarationFragment vdf : fragments) { + if (vdf.getName().toString().equals(name)) + return fd; + } + } + } else if (constrains.contains(ASTNode.METHOD_DECLARATION)) { + // look for methods + MethodDeclaration[] methods = td.getMethods(); + for (MethodDeclaration md : methods) { + if (md.getName().toString().equals(name)) { + return md; + } + } + } + } + break; + case ASTNode.METHOD_DECLARATION: + System.err.println(getNodeAsString(node)); + if (((MethodDeclaration) node).getName().toString().equals(name)) + return node; + break; + case ASTNode.SINGLE_VARIABLE_DECLARATION: + System.err.println(getNodeAsString(node)); + if (((SingleVariableDeclaration) node).getName().toString().equals(name)) + return node; + break; + case ASTNode.FIELD_DECLARATION: + System.err.println("FD" + node); + vdfList = ((FieldDeclaration) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + System.err.println("VDE" + node); + vdfList = ((VariableDeclarationExpression) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + System.err.println("VDS" + node); + vdfList = ((VariableDeclarationStatement) node).fragments(); + break; + + default: + + } + if (vdfList != null) { + for (VariableDeclarationFragment vdf : vdfList) { + if (vdf.getName().toString().equals(name)) + return node; + } + } + return null; + } + + public static boolean isAddableASTNode(ASTNode node) { + return true; + } + + static private String getNodeAsString(ASTNode node) { + if (node == null) + return "NULL"; + String className = node.getClass().getName(); + int index = className.lastIndexOf("."); + if (index > 0) + className = className.substring(index + 1); + + // if(node instanceof BodyDeclaration) + // return className; + + String value = className; + + if (node instanceof TypeDeclaration) + value = ((TypeDeclaration) node).getName().toString() + " | " + className; + else if (node instanceof MethodDeclaration) + value = ((MethodDeclaration) node).getName().toString() + " | " + + className; + else if (node instanceof MethodInvocation) + value = ((MethodInvocation) node).getName().toString() + " | " + + className; + else if (node instanceof FieldDeclaration) + value = ((FieldDeclaration) node).toString() + " FldDecl| "; + else if (node instanceof SingleVariableDeclaration) + value = ((SingleVariableDeclaration) node).getName() + " - " + + ((SingleVariableDeclaration) node).getType() + " | SVD "; + else if (node instanceof ExpressionStatement) + value = node.toString() + className; + else if (node instanceof SimpleName) + value = ((SimpleName) node).getFullyQualifiedName() + " | " + className; + else if (className.startsWith("Variable")) + value = node.toString() + " | " + className; + else if (className.endsWith("Type")) + value = node.toString() + " |" + className; + value += " [" + node.getStartPosition() + "," + + (node.getStartPosition() + node.getLength()) + "]"; + value += " Line: " + + ((CompilationUnit) node.getRoot()).getLineNumber(node + .getStartPosition()); + return value; + } + + public static String readFile(String path) { + BufferedReader reader = null; + try { + reader = new BufferedReader( + new InputStreamReader( + new FileInputStream( + new File( + path)))); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + try { + StringBuilder ret = new StringBuilder(); + // ret.append("package " + className + ";\n"); + String line; + while ((line = reader.readLine()) != null) { + ret.append(line); + ret.append("\n"); + } + return ret.toString(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } + +} diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 91bf862b9..b8f44a05b 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -179,7 +179,9 @@ public class DebugEditor extends JavaEditor implements ActionListener { checkForJavaTabs(); initializeErrorChecker(); ta.setECSandThemeforTextArea(errorCheckerService, dmode); - addXQModeUI(); + addXQModeUI(); + //TODO: Remove this later + setBounds(160, 400, getWidth(), getHeight()); } private void addXQModeUI(){ diff --git a/pdex/src/processing/mode/experimental/ErrorBar.java b/pdex/src/processing/mode/experimental/ErrorBar.java index b21aaac40..24d552ae5 100755 --- a/pdex/src/processing/mode/experimental/ErrorBar.java +++ b/pdex/src/processing/mode/experimental/ErrorBar.java @@ -187,11 +187,12 @@ public class ErrorBar extends JPanel { // Each problem.getSourceLine() will have an extra line added // because of - // class declaration in the beginning + // class declaration in the beginning as well as default imports for (Problem problem : problems) { if (problem.tabIndex == currentTab) { // Ratio of error line to total lines - float y = problem.lineNumber / ((float) totalLines); + float y = (problem.lineNumber - errorCheckerService.defaultImportsOffset) + / ((float) totalLines); // Ratio multiplied by height of the error bar y *= fheight - 15; // -15 is just a vertical offset errorPoints.add(new ErrorMarker(problem, (int) y, diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java old mode 100755 new mode 100644 index 435d54903..e0ce2a646 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -28,6 +28,7 @@ import processing.app.Base; import processing.app.Library; import processing.app.SketchCode; import processing.core.PApplet; +import processing.mode.java.preproc.PdePreprocessor; public class ErrorCheckerService implements Runnable{ @@ -87,6 +88,11 @@ public class ErrorCheckerService implements Runnable{ */ public int mainClassOffset; + /** + * Fixed p5 offsets for all sketches + */ + public int defaultImportsOffset; + /** * Is the sketch running in static mode or active mode? */ @@ -173,6 +179,9 @@ public class ErrorCheckerService implements Runnable{ initParser(); initializeErrorWindow(); xqpreproc = new XQPreprocessor(); + PdePreprocessor pdePrepoc = new PdePreprocessor(null); + defaultImportsOffset = pdePrepoc.getCoreImports().length + + pdePrepoc.getDefaultImports().length + 1; } /** @@ -222,11 +231,6 @@ public class ErrorCheckerService implements Runnable{ }); } - /** - * checkCode() only on text area update - */ - protected AtomicInteger textModified = new AtomicInteger(0); - public void run() { stopThread = false; @@ -239,62 +243,62 @@ public class ErrorCheckerService implements Runnable{ System.out.println("Oops! [ErrorCheckerThreaded]: " + e); // e.printStackTrace(); } - + + updatePaintedThingys(); + if (pauseThread) continue; - - updatePaintedThingy(); - if(textModified.get() == 0) continue; - // Check every x seconds checkCode(); } } - - - + ASTGenerator astGenerator = new ASTGenerator(this); + AtomicInteger textModified = new AtomicInteger(); private boolean checkCode() { - + System.out.println("checkCode() " + textModified.get() ); lastTimeStamp = System.currentTimeMillis(); try { sourceCode = preprocessCode(editor.getSketch().getMainProgram()); syntaxCheck(); - + System.err.println(editor.getSketch().getName()+ " MCO " + mainClassOffset); // No syntax errors, proceed for compilation check, Stage 2. + if (problems.length == 0 && editor.compilationCheckEnabled) { + astGenerator.buildAST(); sourceCode = xqpreproc.doYourThing(sourceCode, programImports); prepareCompilerClasspath(); - mainClassOffset = xqpreproc.mainClassOffset; // tiny, but - // significant - if (staticMode) { - mainClassOffset++; // Extra line for setup() decl. - } +// mainClassOffset = xqpreproc.mainClassOffset; // tiny, but +// // significant +// if (staticMode) { +// mainClassOffset++; // Extra line for setup() decl. +// } // System.out.println(sourceCode); // System.out.println("--------------------------"); compileCheck(); + } updateErrorTable(); editor.updateErrorBar(problemsList); updateEditorStatus(); - // updatePaintedThingy(); + updatePaintedThingys(); int x = textModified.get(); //System.out.println("TM " + x); if(x>=3){ - textModified.set(3); - x = 3; + textModified.set(3); + x = 3; } if(x>0) - textModified.set(x - 1); + textModified.set(x - 1); else - textModified.set(0); + textModified.set(0); return true; } catch (Exception e) { @@ -675,14 +679,15 @@ public class ErrorCheckerService implements Runnable{ /** * Repaints the textarea if required */ - public void updatePaintedThingy() { + public void updatePaintedThingys() { editor.getTextArea().repaint(); updateEditorStatus(); currentTab = editor.getSketch().getCodeIndex( editor.getSketch().getCurrentCode()); + //System.out.println("awesome! " + currentTab + " LT " + lastTab); if (currentTab != lastTab) { + textModified.incrementAndGet(); lastTab = currentTab; - editor.updateErrorBar(problemsList); return; } @@ -725,7 +730,7 @@ public class ErrorCheckerService implements Runnable{ // String[] lines = {};// = PApplet.split(sourceString, '\n'); int codeIndex = 0; - int x = problem.getSourceLineNumber() - mainClassOffset; + int x = problem.getSourceLineNumber() - mainClassOffset + 1; if (x < 0) { // System.out.println("Negative line number " // + problem.getSourceLineNumber() + " , offset " @@ -900,23 +905,31 @@ public class ErrorCheckerService implements Runnable{ className = (editor == null) ? "DefaultClass" : editor.getSketch() .getName(); + // Check whether the code is being written in STATIC mode(no function // declarations) - append class declaration and void setup() declaration Matcher matcher = FUNCTION_DECL.matcher(sourceAlt); if (!matcher.find()) { - sourceAlt = "public class " + className + " extends PApplet {\n" + sourceAlt = xqpreproc.prepareImports(programImports) + "public class " + className + " extends PApplet {\n" + "public void setup() {\n" + sourceAlt + "\nnoLoop();\n}\n" + "\n}\n"; - staticMode = true; - mainClassOffset = 2; + staticMode = true; } else { - sourceAlt = "public class " + className + " extends PApplet {\n" + sourceAlt = xqpreproc.prepareImports(programImports) + "public class " + className + " extends PApplet {\n" + sourceAlt + "\n}"; - staticMode = false; - mainClassOffset = 1; + staticMode = false; } - + + int position = sourceAlt.indexOf("{") + 1; + mainClassOffset = 1; + for (int i = 0; i <= position; i++) { + if (sourceAlt.charAt(i) == '\n') { + mainClassOffset++; + } + } + if(staticMode) mainClassOffset++; + //mainClassOffset += 2; // Handle unicode characters sourceAlt = substituteUnicode(sourceAlt); @@ -963,6 +976,36 @@ public class ErrorCheckerService implements Runnable{ } } + public void scrollToErrorLine(Problem p) { + if (editor == null) { + return; + } + if(p==null) + return; + try { + editor.toFront(); + editor.getSketch().setCurrentCode(p.tabIndex); + + editor.setSelection(editor.getTextArea() + .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1) + + editor.getTextArea().getLineText(p.lineNumber - 1) + .trim().length(), editor.getTextArea() + .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1)); + editor.getTextArea().scrollTo(p.lineNumber - 1, 0); + editor.repaint(); + } catch (Exception e) { + System.err + .println(e + + " : Error while selecting text in scrollToErrorLine()"); + e.printStackTrace(); + } + // System.out.println("---"); + + + } + + + /** * Checks if import statements in the sketch have changed. If they have, * compiler classpath needs to be updated. @@ -1000,7 +1043,7 @@ public class ErrorCheckerService implements Runnable{ * @return String - Tab code with imports replaced with white spaces */ private String scrapImportStatements(String tabProgram, int tabNumber) { - + //TODO: Commented out imports are still detected as main imports. String tabSource = new String(tabProgram); do { // System.out.println("-->\n" + sourceAlt + "\n<--"); @@ -1025,7 +1068,7 @@ public class ErrorCheckerService implements Runnable{ programImports.add(new ImportStatement(piece, tabNumber, Base .countLines(tabSource.substring(0, idx)))); // Remove the import from the main program - // Substitue with white spaces + // Substitute with white spaces String whiteSpace = ""; for (int j = 0; j < piece.length(); j++) { whiteSpace += " "; diff --git a/pdex/src/processing/mode/experimental/Problem.java b/pdex/src/processing/mode/experimental/Problem.java old mode 100755 new mode 100644 index 6b5b95ff4..56cc0e833 --- a/pdex/src/processing/mode/experimental/Problem.java +++ b/pdex/src/processing/mode/experimental/Problem.java @@ -130,7 +130,7 @@ public class Problem { public static String process(String message) { // Remove all instances of token // "Syntax error on token 'blah', delete this token" - + if(message == null) return null; pattern = Pattern.compile(tokenRegExp); matcher = pattern.matcher(message); message = matcher.replaceAll(""); diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java old mode 100755 new mode 100644 index 87722498a..a90d9c6b6 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -33,318 +33,462 @@ import processing.app.syntax.TextAreaDefaults; /** * Customized text area. Adds support for line background colors. - * + * * @author Martin Leopold */ public class TextArea extends JEditTextArea { - protected MouseListener[] mouseListeners; // cached mouselisteners, these are wrapped by MouseHandler - protected DebugEditor editor; // the editor - // line properties - protected Map lineColors = new HashMap(); // contains line background colors - // left-hand gutter properties - protected int gutterPadding = 3; // [px] space added to the left and right of gutter chars - protected Color gutterBgColor = new Color(252, 252, 252); // gutter background color - protected Color gutterLineColor = new Color(233, 233, 233); // color of vertical separation line - protected String breakpointMarker = "<>"; // the text marker for highlighting breakpoints in the gutter - protected String currentLineMarker = "->"; // the text marker for highlighting the current line in the gutter - protected Map gutterText = new HashMap(); // maps line index to gutter text - protected Map gutterTextColors = new HashMap(); // maps line index to gutter text color - protected TextAreaPainter customPainter; - protected ErrorCheckerService errorCheckerService; - - public TextArea(TextAreaDefaults defaults, DebugEditor editor) { - super(defaults); - this.editor = editor; + protected MouseListener[] mouseListeners; // cached mouselisteners, these are wrapped by MouseHandler - // replace the painter: - // first save listeners, these are package-private in JEditTextArea, so not accessible - ComponentListener[] componentListeners = painter.getComponentListeners(); - mouseListeners = painter.getMouseListeners(); - MouseMotionListener[] mouseMotionListeners = painter.getMouseMotionListeners(); + protected DebugEditor editor; // the editor - remove(painter); + // line properties + protected Map lineColors = new HashMap(); // contains line background colors - // set new painter - customPainter = new TextAreaPainter(this, defaults); - painter = customPainter; - - // set listeners - for (ComponentListener cl : componentListeners) { - painter.addComponentListener(cl); - } + // left-hand gutter properties + protected int gutterPadding = 3; // [px] space added to the left and right of gutter chars - for (MouseMotionListener mml : mouseMotionListeners) { - painter.addMouseMotionListener(mml); - } + protected Color gutterBgColor = new Color(252, 252, 252); // gutter background color - // use a custom mouse handler instead of directly using mouseListeners - MouseHandler mouseHandler = new MouseHandler(); - painter.addMouseListener(mouseHandler); - painter.addMouseMotionListener(mouseHandler); + protected Color gutterLineColor = new Color(233, 233, 233); // color of vertical separation line - add(CENTER, painter); + protected String breakpointMarker = "<>"; // the text marker for highlighting breakpoints in the gutter - // load settings from theme.txt - ExperimentalMode theme = (ExperimentalMode) editor.getMode(); - gutterBgColor = theme.getThemeColor("gutter.bgcolor", gutterBgColor); - gutterLineColor = theme.getThemeColor("gutter.linecolor", gutterLineColor); - gutterPadding = theme.getInteger("gutter.padding"); - breakpointMarker = theme.loadThemeString("breakpoint.marker", breakpointMarker); - currentLineMarker = theme.loadThemeString("currentline.marker", currentLineMarker); + protected String currentLineMarker = "->"; // the text marker for highlighting the current line in the gutter + + protected Map gutterText = new HashMap(); // maps line index to gutter text + + protected Map gutterTextColors = new HashMap(); // maps line index to gutter text color + + protected TextAreaPainter customPainter; + + protected ErrorCheckerService errorCheckerService; + + public TextArea(TextAreaDefaults defaults, DebugEditor editor) { + super(defaults); + this.editor = editor; + + // replace the painter: + // first save listeners, these are package-private in JEditTextArea, so not accessible + ComponentListener[] componentListeners = painter.getComponentListeners(); + mouseListeners = painter.getMouseListeners(); + MouseMotionListener[] mouseMotionListeners = painter + .getMouseMotionListeners(); + + remove(painter); + + // set new painter + customPainter = new TextAreaPainter(this, defaults); + painter = customPainter; + + // set listeners + for (ComponentListener cl : componentListeners) { + painter.addComponentListener(cl); } - - /** - * Sets ErrorCheckerService and loads theme for TextArea(XQMode) - * @param ecs - * @param mode + + for (MouseMotionListener mml : mouseMotionListeners) { + painter.addMouseMotionListener(mml); + } + + // use a custom mouse handler instead of directly using mouseListeners + MouseHandler mouseHandler = new MouseHandler(); + painter.addMouseListener(mouseHandler); + painter.addMouseMotionListener(mouseHandler); + + add(CENTER, painter); + + // load settings from theme.txt + ExperimentalMode theme = (ExperimentalMode) editor.getMode(); + gutterBgColor = theme.getThemeColor("gutter.bgcolor", gutterBgColor); + gutterLineColor = theme.getThemeColor("gutter.linecolor", gutterLineColor); + gutterPadding = theme.getInteger("gutter.padding"); + breakpointMarker = theme.loadThemeString("breakpoint.marker", + breakpointMarker); + currentLineMarker = theme.loadThemeString("currentline.marker", + currentLineMarker); + } + + /** + * Sets ErrorCheckerService and loads theme for TextArea(XQMode) + * + * @param ecs + * @param mode + */ + public void setECSandThemeforTextArea(ErrorCheckerService ecs, + ExperimentalMode mode) { + errorCheckerService = ecs; + customPainter.setECSandTheme(ecs, mode); + } + + public void processKeyEvent(KeyEvent evt) { + super.processKeyEvent(evt); + if (evt.getID() == KeyEvent.KEY_TYPED) { + errorCheckerService.textModified.incrementAndGet(); + System.out.println(" Typing: " + fetchPhrase(evt) + " " + + (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE)); + + } + + } + + private String fetchPhrase(KeyEvent evt) { + int off = getCaretPosition(); + System.out.print("off " + off); + if (off < 0) + return null; + int line = getCaretLine(); + if (line < 0) + return null; + String s = getLineText(line); + System.out.print("lin " + line); + /* + * if (s == null) return null; else if (s.length() == 0) return null; */ - public void setECSandThemeforTextArea(ErrorCheckerService ecs, ExperimentalMode mode) - { - errorCheckerService = ecs; - customPainter.setECSandTheme(ecs, mode); - } - - public void processKeyEvent(KeyEvent evt) { - super.processKeyEvent(evt); - if(evt.getID() == KeyEvent.KEY_TYPED){ - errorCheckerService.textModified.incrementAndGet(); - } - } +// else { + //System.out.print(s + " len " + s.length()); - /** - * Retrieve the total width of the gutter area. - * - * @return gutter width in pixels - */ - protected int getGutterWidth() { - FontMetrics fm = painter.getFontMetrics(); + int x = getCaretPosition() - getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1; + System.out.print(" x char: " + s.charAt(x)); + //int xLS = off - getLineStartNonWhiteSpaceOffset(line); + char keyChar = evt.getKeyChar(); + if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) + ; // accepted these keys + else if (keyChar == KeyEvent.CHAR_UNDEFINED) + + return null; + + String word = (x < s.length() ? s.charAt(x) : "") + ""; + if (s.trim().length() == 1) { +// word = "" +// + (keyChar == KeyEvent.CHAR_UNDEFINED ? s.charAt(x - 1) : keyChar); + //word = (x < s.length()?s.charAt(x):"") + ""; + word = word.trim(); + if (word.endsWith(".")) + word = word.substring(0, word.length() - 1); + errorCheckerService.astGenerator.updatePredictions(word, line + + errorCheckerService.mainClassOffset); + return word; + } +// if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) +// ; // accepted these keys +// else if (!(Character.isLetterOrDigit(keyChar) || keyChar == '_' || keyChar == '$')) +// return null; + int i = 0; + int closeB = 0; + + while (true) { + i++; + //TODO: currently works on single line only. "a. b()" won't be detected + if (x1 >= 0) { +// if (s.charAt(x1) != ';' && s.charAt(x1) != ',' && s.charAt(x1) != '(') + if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_' + || s.charAt(x1) == '.' || s.charAt(x1) == ')') + { + + if (s.charAt(x1) == ')') { + word = s.charAt(x1--) + word; + closeB++; + while (x1 >= 0 && closeB > 0) { + word = s.charAt(x1) + word; + if (s.charAt(x1) == '(') + closeB--; + if (s.charAt(x1) == ')') + closeB++; + x1--; + } + } else { + word = s.charAt(x1--) + word; + } + } else { + break; + } + } else { + break; + } + +// if (x2 >= 0 && x2 < s.length()) { +// if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' +// || s.charAt(x2) == '$') +// word = word + s.charAt(x2++); +// else +// x2 = -1; +// } else +// x2 = -1; + +// if (x1 < 0 )//&& x2 < 0 +// break; + if (i > 200) { + // time out! + System.err.println("Whoopsy! :P"); + break; + } + } +// if (keyChar != KeyEvent.CHAR_UNDEFINED) + + if (Character.isDigit(word.charAt(0))) + return null; + word = word.trim(); + if (word.endsWith(".")) + word = word.substring(0, word.length() - 1); + errorCheckerService.astGenerator.updatePredictions(word, line + + errorCheckerService.mainClassOffset); + return word; + + //} + } + + /** + * Retrieve the total width of the gutter area. + * + * @return gutter width in pixels + */ + protected int getGutterWidth() { + FontMetrics fm = painter.getFontMetrics(); // System.out.println("fm: " + (fm == null)); // System.out.println("editor: " + (editor == null)); - //System.out.println("BPBPBPBPB: " + (editor.breakpointMarker == null)); + //System.out.println("BPBPBPBPB: " + (editor.breakpointMarker == null)); - int textWidth = Math.max(fm.stringWidth(breakpointMarker), fm.stringWidth(currentLineMarker)); - return textWidth + 2 * gutterPadding; + int textWidth = Math.max(fm.stringWidth(breakpointMarker), + fm.stringWidth(currentLineMarker)); + return textWidth + 2 * gutterPadding; + } + + /** + * Retrieve the width of margins applied to the left and right of the gutter + * text. + * + * @return margins in pixels + */ + protected int getGutterMargins() { + return gutterPadding; + } + + /** + * Set the gutter text of a specific line. + * + * @param lineIdx + * the line index (0-based) + * @param text + * the text + */ + public void setGutterText(int lineIdx, String text) { + gutterText.put(lineIdx, text); + painter.invalidateLine(lineIdx); + } + + /** + * Set the gutter text and color of a specific line. + * + * @param lineIdx + * the line index (0-based) + * @param text + * the text + * @param textColor + * the text color + */ + public void setGutterText(int lineIdx, String text, Color textColor) { + gutterTextColors.put(lineIdx, textColor); + setGutterText(lineIdx, text); + } + + /** + * Clear the gutter text of a specific line. + * + * @param lineIdx + * the line index (0-based) + */ + public void clearGutterText(int lineIdx) { + gutterText.remove(lineIdx); + painter.invalidateLine(lineIdx); + } + + /** + * Clear all gutter text. + */ + public void clearGutterText() { + for (int lineIdx : gutterText.keySet()) { + painter.invalidateLine(lineIdx); } + gutterText.clear(); + } - /** - * Retrieve the width of margins applied to the left and right of the gutter - * text. - * - * @return margins in pixels - */ - protected int getGutterMargins() { - return gutterPadding; + /** + * Retrieve the gutter text of a specific line. + * + * @param lineIdx + * the line index (0-based) + * @return the gutter text + */ + public String getGutterText(int lineIdx) { + return gutterText.get(lineIdx); + } + + /** + * Retrieve the gutter text color for a specific line. + * + * @param lineIdx + * the line index + * @return the gutter text color + */ + public Color getGutterTextColor(int lineIdx) { + return gutterTextColors.get(lineIdx); + } + + /** + * Set the background color of a line. + * + * @param lineIdx + * 0-based line number + * @param col + * the background color to set + */ + public void setLineBgColor(int lineIdx, Color col) { + lineColors.put(lineIdx, col); + painter.invalidateLine(lineIdx); + } + + /** + * Clear the background color of a line. + * + * @param lineIdx + * 0-based line number + */ + public void clearLineBgColor(int lineIdx) { + lineColors.remove(lineIdx); + painter.invalidateLine(lineIdx); + } + + /** + * Clear all line background colors. + */ + public void clearLineBgColors() { + for (int lineIdx : lineColors.keySet()) { + painter.invalidateLine(lineIdx); } + lineColors.clear(); + } - /** - * Set the gutter text of a specific line. - * - * @param lineIdx the line index (0-based) - * @param text the text - */ - public void setGutterText(int lineIdx, String text) { - gutterText.put(lineIdx, text); - painter.invalidateLine(lineIdx); - } + /** + * Get a lines background color. + * + * @param lineIdx + * 0-based line number + * @return the color or null if no color was set for the specified line + */ + public Color getLineBgColor(int lineIdx) { + return lineColors.get(lineIdx); + } - /** - * Set the gutter text and color of a specific line. - * - * @param lineIdx the line index (0-based) - * @param text the text - * @param textColor the text color - */ - public void setGutterText(int lineIdx, String text, Color textColor) { - gutterTextColors.put(lineIdx, textColor); - setGutterText(lineIdx, text); - } + /** + * Convert a character offset to a horizontal pixel position inside the text + * area. Overridden to take gutter width into account. + * + * @param line + * the 0-based line number + * @param offset + * the character offset (0 is the first character on a line) + * @return the horizontal position + */ + @Override + public int _offsetToX(int line, int offset) { + return super._offsetToX(line, offset) + getGutterWidth(); + } - /** - * Clear the gutter text of a specific line. - * - * @param lineIdx the line index (0-based) - */ - public void clearGutterText(int lineIdx) { - gutterText.remove(lineIdx); - painter.invalidateLine(lineIdx); - } + /** + * Convert a horizontal pixel position to a character offset. Overridden to + * take gutter width into account. + * + * @param line + * the 0-based line number + * @param x + * the horizontal pixel position + * @return he character offset (0 is the first character on a line) + */ + @Override + public int xToOffset(int line, int x) { + return super.xToOffset(line, x - getGutterWidth()); + } - /** - * Clear all gutter text. - */ - public void clearGutterText() { - for (int lineIdx : gutterText.keySet()) { - painter.invalidateLine(lineIdx); - } - gutterText.clear(); - } + /** + * Custom mouse handler. Implements double clicking in the gutter area to + * toggle breakpoints, sets default cursor (instead of text cursor) in the + * gutter area. + */ + protected class MouseHandler implements MouseListener, MouseMotionListener { - /** - * Retrieve the gutter text of a specific line. - * - * @param lineIdx the line index (0-based) - * @return the gutter text - */ - public String getGutterText(int lineIdx) { - return gutterText.get(lineIdx); - } + protected int lastX; // previous horizontal positon of the mouse cursor - /** - * Retrieve the gutter text color for a specific line. - * - * @param lineIdx the line index - * @return the gutter text color - */ - public Color getGutterTextColor(int lineIdx) { - return gutterTextColors.get(lineIdx); - } - - /** - * Set the background color of a line. - * - * @param lineIdx 0-based line number - * @param col the background color to set - */ - public void setLineBgColor(int lineIdx, Color col) { - lineColors.put(lineIdx, col); - painter.invalidateLine(lineIdx); - } - - /** - * Clear the background color of a line. - * - * @param lineIdx 0-based line number - */ - public void clearLineBgColor(int lineIdx) { - lineColors.remove(lineIdx); - painter.invalidateLine(lineIdx); - } - - /** - * Clear all line background colors. - */ - public void clearLineBgColors() { - for (int lineIdx : lineColors.keySet()) { - painter.invalidateLine(lineIdx); - } - lineColors.clear(); - } - - /** - * Get a lines background color. - * - * @param lineIdx 0-based line number - * @return the color or null if no color was set for the specified line - */ - public Color getLineBgColor(int lineIdx) { - return lineColors.get(lineIdx); - } - - /** - * Convert a character offset to a horizontal pixel position inside the text - * area. Overridden to take gutter width into account. - * - * @param line the 0-based line number - * @param offset the character offset (0 is the first character on a line) - * @return the horizontal position - */ @Override - public int _offsetToX(int line, int offset) { - return super._offsetToX(line, offset) + getGutterWidth(); + public void mouseClicked(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseClicked(me); + } } - /** - * Convert a horizontal pixel position to a character offset. Overridden to - * take gutter width into account. - * - * @param line the 0-based line number - * @param x the horizontal pixel position - * @return he character offset (0 is the first character on a line) - */ @Override - public int xToOffset(int line, int x) { - return super.xToOffset(line, x - getGutterWidth()); + public void mousePressed(MouseEvent me) { + // check if this happened in the gutter area + if (me.getX() < getGutterWidth()) { + if (me.getButton() == MouseEvent.BUTTON1 && me.getClickCount() == 2) { + int line = me.getY() / painter.getFontMetrics().getHeight() + + firstLine; + if (line >= 0 && line <= getLineCount() - 1) { + editor.gutterDblClicked(line); + } + } + } else { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mousePressed(me); + } + } } - /** - * Custom mouse handler. Implements double clicking in the gutter area to - * toggle breakpoints, sets default cursor (instead of text cursor) in the - * gutter area. - */ - protected class MouseHandler implements MouseListener, MouseMotionListener { - - protected int lastX; // previous horizontal positon of the mouse cursor - - @Override - public void mouseClicked(MouseEvent me) { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mouseClicked(me); - } - } - - @Override - public void mousePressed(MouseEvent me) { - // check if this happened in the gutter area - if (me.getX() < getGutterWidth()) { - if (me.getButton() == MouseEvent.BUTTON1 && me.getClickCount() == 2) { - int line = me.getY() / painter.getFontMetrics().getHeight() + firstLine; - if (line >= 0 && line <= getLineCount() - 1) { - editor.gutterDblClicked(line); - } - } - } else { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mousePressed(me); - } - } - } - - @Override - public void mouseReleased(MouseEvent me) { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mouseReleased(me); - } - } - - @Override - public void mouseEntered(MouseEvent me) { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mouseEntered(me); - } - } - - @Override - public void mouseExited(MouseEvent me) { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mouseExited(me); - } - } - - @Override - public void mouseDragged(MouseEvent me) { - // No need to forward since the standard MouseMotionListeners are called anyway - // nop - } - - @Override - public void mouseMoved(MouseEvent me) { - // No need to forward since the standard MouseMotionListeners are called anyway - if (me.getX() < getGutterWidth()) { - if (lastX >= getGutterWidth()) { - painter.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - } - } else { - if (lastX < getGutterWidth()) { - painter.setCursor(new Cursor(Cursor.TEXT_CURSOR)); - } - } - lastX = me.getX(); - } + @Override + public void mouseReleased(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseReleased(me); + } } + + @Override + public void mouseEntered(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseEntered(me); + } + } + + @Override + public void mouseExited(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseExited(me); + } + } + + @Override + public void mouseDragged(MouseEvent me) { + // No need to forward since the standard MouseMotionListeners are called anyway + // nop + } + + @Override + public void mouseMoved(MouseEvent me) { + // No need to forward since the standard MouseMotionListeners are called anyway + if (me.getX() < getGutterWidth()) { + if (lastX >= getGutterWidth()) { + painter.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + } else { + if (lastX < getGutterWidth()) { + painter.setCursor(new Cursor(Cursor.TEXT_CURSOR)); + } + } + lastX = me.getX(); + } + } + } diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java old mode 100755 new mode 100644 index 8c93978f2..76dd2b3c6 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -19,6 +19,13 @@ package processing.mode.experimental; import java.awt.Color; import java.awt.Graphics; +import java.awt.Toolkit; +import java.awt.event.InputEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import javax.swing.text.BadLocationException; import javax.swing.text.Segment; @@ -26,293 +33,457 @@ import javax.swing.text.Utilities; import processing.app.syntax.TextAreaDefaults; import processing.app.syntax.TokenMarker; +import processing.mode.experimental.ASTGenerator.ASTNodeWrapper; /** * Customized line painter. Adds support for background colors, left hand gutter * area with background color and text. - * + * * @author Martin Leopold */ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { - protected TextArea ta; // we need the subclassed textarea - protected ErrorCheckerService errorCheckerService; - - /** - * Error line underline color - */ - public Color errorColor = new Color(0xED2630); + protected TextArea ta; // we need the subclassed textarea - /** - * Warning line underline color - */ + protected ErrorCheckerService errorCheckerService; - public Color warningColor = new Color(0xFFC30E); + /** + * Error line underline color + */ + public Color errorColor = new Color(0xED2630); - /** - * Color of Error Marker - */ - public Color errorMarkerColor = new Color(0xED2630); + /** + * Warning line underline color + */ - /** - * Color of Warning Marker - */ - public Color warningMarkerColor = new Color(0xFFC30E); - - public TextAreaPainter(TextArea textArea, TextAreaDefaults defaults) { - super(textArea, defaults); - ta = textArea; - } - - private void loadTheme(ExperimentalMode mode){ - errorColor = mode.getThemeColor("editor.errorcolor", errorColor); - warningColor = mode.getThemeColor("editor.warningcolor", - warningColor); - errorMarkerColor = mode.getThemeColor("editor.errormarkercolor", - errorMarkerColor); - warningMarkerColor = mode.getThemeColor( - "editor.warningmarkercolor", warningMarkerColor); - } + public Color warningColor = new Color(0xFFC30E); - /** - * Paint a line. Paints the gutter (with background color and text) then the - * line (background color and text). - * - * @param gfx the graphics context - * @param tokenMarker - * @param line 0-based line number - * @param x horizontal position - */ - @Override - protected void paintLine(Graphics gfx, TokenMarker tokenMarker, - int line, int x) { + /** + * Color of Error Marker + */ + public Color errorMarkerColor = new Color(0xED2630); - // paint gutter - paintGutterBg(gfx, line, x); + /** + * Color of Warning Marker + */ + public Color warningMarkerColor = new Color(0xFFC30E); - paintLineBgColor(gfx, line, x + ta.getGutterWidth()); + static int ctrlMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); - paintGutterLine(gfx, line, x); - - // paint gutter symbol - paintGutterText(gfx, line, x); - - paintErrorLine(gfx, line, x); - - super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); - } - - /** - * Paint the gutter background (solid color). - * - * @param gfx the graphics context - * @param line 0-based line number - * @param x horizontal position - */ - protected void paintGutterBg(Graphics gfx, int line, int x) { - gfx.setColor(ta.gutterBgColor); - int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); - gfx.fillRect(0, y, ta.getGutterWidth(), fm.getHeight()); - } - - /** - * Paint the vertical gutter separator line. - * - * @param gfx the graphics context - * @param line 0-based line number - * @param x horizontal position - */ - protected void paintGutterLine(Graphics gfx, int line, int x) { - int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); - gfx.setColor(ta.gutterLineColor); - gfx.drawLine(ta.getGutterWidth(), y, ta.getGutterWidth(), y + fm.getHeight()); - } - - /** - * Paint the gutter text. - * - * @param gfx the graphics context - * @param line 0-based line number - * @param x horizontal position - */ - protected void paintGutterText(Graphics gfx, int line, int x) { - String text = ta.getGutterText(line); - if (text == null) { - return; - } - - gfx.setFont(getFont()); - Color textColor = ta.getGutterTextColor(line); - if (textColor == null) { - gfx.setColor(getForeground()); - } else { - gfx.setColor(textColor); - } - int y = ta.lineToY(line) + fm.getHeight(); - - // draw 4 times to make it appear bold, displaced 1px to the right, to the bottom and bottom right. - //int len = text.length() > ta.gutterChars ? ta.gutterChars : text.length(); - Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins(), y, gfx, this, 0); - Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins() + 1, y, gfx, this, 0); - Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins(), y + 1, gfx, this, 0); - Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins() + 1, y + 1, gfx, this, 0); - } - - /** - * Paint the background color of a line. - * - * @param gfx the graphics context - * @param line 0-based line number - * @param x - */ - protected void paintLineBgColor(Graphics gfx, int line, int x) { - int y = ta.lineToY(line); - y += fm.getLeading() + fm.getMaxDescent(); - int height = fm.getHeight(); - - // get the color - Color col = ta.getLineBgColor(line); - //System.out.print("bg line " + line + ": "); - // no need to paint anything - if (col == null) { - //System.out.println("none"); - return; - } - // paint line background - gfx.setColor(col); - gfx.fillRect(0, y, getWidth(), height); - } - - /** - * Paints the underline for an error/warning line - * - * @param gfx - * the graphics context - * @param tokenMarker - * @param line - * 0-based line number: NOTE - * @param x - */ - protected void paintErrorLine(Graphics gfx, int line, int x) { - - if (errorCheckerService == null) { - return; + public TextAreaPainter(TextArea textArea, TextAreaDefaults defaults) { + super(textArea, defaults); + ta = textArea; + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent evt) { +// System.out.println( " Meta,Ctrl "+ (evt.getModifiers() & ctrlMask)); + if (evt.isControlDown()) + handleCtrlClick(evt); } - - if (errorCheckerService.problemsList== null) { - return; - } - - boolean notFound = true; - boolean isWarning = false; + }); - // Check if current line contains an error. If it does, find if it's an - // error or warning - for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) { - if (emarker.problem.lineNumber == line + 1) { - notFound = false; - if (emarker.type == ErrorMarker.Warning) { - isWarning = true; - } + } + +// public void processKeyEvent(KeyEvent evt) { +// System.out.println(evt); +// } + + void handleCtrlClick(MouseEvent evt) { + System.out.println("--handleCtrlClick--"); + int off = ta.xyToOffset(evt.getX(), evt.getY()); + if (off < 0) + return; + int line = ta.getLineOfOffset(off); + if (line < 0) + return; + String s = ta.getLineText(line); + if (s == null) + return; + else if (s.length() == 0) + return; + else { + int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; + int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); + if (x < 0 || x >= s.length()) + return; + String word = s.charAt(x) + ""; + if (s.charAt(x) == ' ') + return; + if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s + .charAt(x) == '$')) + return; + int i = 0; + while (true) { + i++; + if (x1 >= 0 && x1 < s.length()) { + if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { + word = s.charAt(x1--) + word; + } else + x1 = -1; + } else + x1 = -1; + + if (x2 >= 0 && x2 < s.length()) { + if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' + || s.charAt(x2) == '$') + word = word + s.charAt(x2++); + else + x2 = -1; + } else + x2 = -1; + + if (x1 < 0 && x2 < 0) + break; + if (i > 200) { + // time out! + System.err.println("Whoopsy! :P"); break; } } - - if (notFound) { + if (Character.isDigit(word.charAt(0))) return; + + System.out.print(errorCheckerService.mainClassOffset + line); + System.out.print("|" + line + "| offset " + xLS + word + " <= \n"); + errorCheckerService.astGenerator.scrollToDeclaration(line + + errorCheckerService.mainClassOffset, word, xLS); + } + } + + private void loadTheme(ExperimentalMode mode) { + errorColor = mode.getThemeColor("editor.errorcolor", errorColor); + warningColor = mode.getThemeColor("editor.warningcolor", warningColor); + errorMarkerColor = mode.getThemeColor("editor.errormarkercolor", + errorMarkerColor); + warningMarkerColor = mode.getThemeColor("editor.warningmarkercolor", + warningMarkerColor); + } + + /** + * Paint a line. Paints the gutter (with background color and text) then the + * line (background color and text). + * + * @param gfx + * the graphics context + * @param tokenMarker + * @param line + * 0-based line number + * @param x + * horizontal position + */ + @Override + protected void paintLine(Graphics gfx, TokenMarker tokenMarker, int line, + int x) { + + // paint gutter + paintGutterBg(gfx, line, x); + + paintLineBgColor(gfx, line, x + ta.getGutterWidth()); + + paintGutterLine(gfx, line, x); + + // paint gutter symbol + paintGutterText(gfx, line, x); + + paintErrorLine(gfx, line, x); + + super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); + } + + /** + * Paint the gutter background (solid color). + * + * @param gfx + * the graphics context + * @param line + * 0-based line number + * @param x + * horizontal position + */ + protected void paintGutterBg(Graphics gfx, int line, int x) { + gfx.setColor(ta.gutterBgColor); + int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); + gfx.fillRect(0, y, ta.getGutterWidth(), fm.getHeight()); + } + + /** + * Paint the vertical gutter separator line. + * + * @param gfx + * the graphics context + * @param line + * 0-based line number + * @param x + * horizontal position + */ + protected void paintGutterLine(Graphics gfx, int line, int x) { + int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); + gfx.setColor(ta.gutterLineColor); + gfx.drawLine(ta.getGutterWidth(), y, ta.getGutterWidth(), + y + fm.getHeight()); + } + + /** + * Paint the gutter text. + * + * @param gfx + * the graphics context + * @param line + * 0-based line number + * @param x + * horizontal position + */ + protected void paintGutterText(Graphics gfx, int line, int x) { + String text = ta.getGutterText(line); + if (text == null) { + return; + } + + gfx.setFont(getFont()); + Color textColor = ta.getGutterTextColor(line); + if (textColor == null) { + gfx.setColor(getForeground()); + } else { + gfx.setColor(textColor); + } + int y = ta.lineToY(line) + fm.getHeight(); + + // draw 4 times to make it appear bold, displaced 1px to the right, to the bottom and bottom right. + //int len = text.length() > ta.gutterChars ? ta.gutterChars : text.length(); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), + ta.getGutterMargins(), y, gfx, this, 0); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), + ta.getGutterMargins() + 1, y, gfx, this, 0); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), + ta.getGutterMargins(), y + 1, gfx, this, 0); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), + ta.getGutterMargins() + 1, y + 1, gfx, this, 0); + } + + /** + * Paint the background color of a line. + * + * @param gfx + * the graphics context + * @param line + * 0-based line number + * @param x + */ + protected void paintLineBgColor(Graphics gfx, int line, int x) { + int y = ta.lineToY(line); + y += fm.getLeading() + fm.getMaxDescent(); + int height = fm.getHeight(); + + // get the color + Color col = ta.getLineBgColor(line); + //System.out.print("bg line " + line + ": "); + // no need to paint anything + if (col == null) { + //System.out.println("none"); + return; + } + // paint line background + gfx.setColor(col); + gfx.fillRect(0, y, getWidth(), height); + } + + /** + * Paints the underline for an error/warning line + * + * @param gfx + * the graphics context + * @param tokenMarker + * @param line + * 0-based line number: NOTE + * @param x + */ + protected void paintErrorLine(Graphics gfx, int line, int x) { + + if (errorCheckerService == null) { + return; + } + + if (errorCheckerService.problemsList == null) { + return; + } + + boolean notFound = true; + boolean isWarning = false; + + // Check if current line contains an error. If it does, find if it's an + // error or warning + for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) { + if (emarker.problem.lineNumber == line + 1) { + notFound = false; + if (emarker.type == ErrorMarker.Warning) { + isWarning = true; + } + break; } - - // Determine co-ordinates - // System.out.println("Hoff " + ta.getHorizontalOffset() + ", " + - // horizontalAdjustment); - int y = ta.lineToY(line); - y += fm.getLeading() + fm.getMaxDescent(); - int height = fm.getHeight(); - int start = ta.getLineStartOffset(line); + } + + if (notFound) { + return; + } + + // Determine co-ordinates + // System.out.println("Hoff " + ta.getHorizontalOffset() + ", " + + // horizontalAdjustment); + int y = ta.lineToY(line); + y += fm.getLeading() + fm.getMaxDescent(); + int height = fm.getHeight(); + int start = ta.getLineStartOffset(line); + + try { + String linetext = null; try { - String linetext = null; - - try { - linetext = ta.getDocument().getText(start, - ta.getLineStopOffset(line) - start - 1); - } catch (BadLocationException bl) { - // Error in the import statements or end of code. - // System.out.print("BL caught. " + ta.getLineCount() + " ," - // + line + " ,"); - // System.out.println((ta.getLineStopOffset(line) - start - 1)); - return; - } - - // Take care of offsets - int aw = fm.stringWidth(trimRight(linetext)) - + ta.getHorizontalOffset(); // apparent width. Whitespaces - // to the left of line + text - // width - int rw = fm.stringWidth(linetext.trim()); // real width - int x1 = 0 + (aw - rw), y1 = y + fm.getHeight() - 2, x2 = x1 + rw; - // Adding offsets for the gutter - x1 += 20; - x2 += 20; - - // gfx.fillRect(x1, y, rw, height); - - // Let the painting begin! - gfx.setColor(errorMarkerColor); - if (isWarning) { - gfx.setColor(warningMarkerColor); - } - gfx.fillRect(1, y + 2, 3, height - 2); - - gfx.setColor(errorColor); - if (isWarning) { - gfx.setColor(warningColor); - } - int xx = x1; - - // Draw the jagged lines - while (xx < x2) { - gfx.drawLine(xx, y1, xx + 2, y1 + 1); - xx += 2; - gfx.drawLine(xx, y1 + 1, xx + 2, y1); - xx += 2; - } - } catch (Exception e) { - System.out - .println("Looks like I messed up! XQTextAreaPainter.paintLine() : " - + e); - //e.printStackTrace(); + linetext = ta.getDocument().getText(start, + ta.getLineStopOffset(line) - start + - 1); + } catch (BadLocationException bl) { + // Error in the import statements or end of code. + // System.out.print("BL caught. " + ta.getLineCount() + " ," + // + line + " ,"); + // System.out.println((ta.getLineStopOffset(line) - start - 1)); + return; } - // Won't highlight the line. Select the text instead. - // gfx.setColor(Color.RED); - // gfx.fillRect(2, y, 3, height); + // Take care of offsets + int aw = fm.stringWidth(trimRight(linetext)) + ta.getHorizontalOffset(); // apparent width. Whitespaces + // to the left of line + text + // width + int rw = fm.stringWidth(linetext.trim()); // real width + int x1 = 0 + (aw - rw), y1 = y + fm.getHeight() - 2, x2 = x1 + rw; + // Adding offsets for the gutter + x1 += 20; + x2 += 20; + + // gfx.fillRect(x1, y, rw, height); + + // Let the painting begin! + gfx.setColor(errorMarkerColor); + if (isWarning) { + gfx.setColor(warningMarkerColor); + } + gfx.fillRect(1, y + 2, 3, height - 2); + + gfx.setColor(errorColor); + if (isWarning) { + gfx.setColor(warningColor); + } + int xx = x1; + + // Draw the jagged lines + while (xx < x2) { + gfx.drawLine(xx, y1, xx + 2, y1 + 1); + xx += 2; + gfx.drawLine(xx, y1 + 1, xx + 2, y1); + xx += 2; + } + } catch (Exception e) { + System.out + .println("Looks like I messed up! XQTextAreaPainter.paintLine() : " + + e); + //e.printStackTrace(); } - - /** - * Trims out trailing whitespaces (to the right) - * - * @param string - * @return - String - */ - private String trimRight(String string) { - String newString = ""; - for (int i = 0; i < string.length(); i++) { - if (string.charAt(i) != ' ') { - newString = string.substring(0, i) + string.trim(); + + // Won't highlight the line. Select the text instead. + // gfx.setColor(Color.RED); + // gfx.fillRect(2, y, 3, height); + } + + /** + * Trims out trailing whitespaces (to the right) + * + * @param string + * @return - String + */ + private String trimRight(String string) { + String newString = ""; + for (int i = 0; i < string.length(); i++) { + if (string.charAt(i) != ' ') { + newString = string.substring(0, i) + string.trim(); + break; + } + } + return newString; + } + + /** + * Sets ErrorCheckerService and loads theme for TextAreaPainter(XQMode) + * + * @param ecs + * @param mode + */ + public void setECSandTheme(ErrorCheckerService ecs, ExperimentalMode mode) { + this.errorCheckerService = ecs; + loadTheme(mode); + } + + public String getToolTipText(java.awt.event.MouseEvent evt) {System.err.println("GET"); + int off = ta.xyToOffset(evt.getX(), evt.getY()); + if (off < 0) + return null; + int line = ta.getLineOfOffset(off); + if (line < 0) + return null; + String s = ta.getLineText(line); + if (s == null) + return evt.toString(); + else if (s.length() == 0) + return null; + else { + int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; + int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); + if (x < 0 || x >= s.length()) + return null; + String word = s.charAt(x) + ""; + if (s.charAt(x) == ' ') + return null; + if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s + .charAt(x) == '$')) + return null; + int i = 0; + while (true) { + i++; + if (x1 >= 0 && x1 < s.length()) { + if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { + word = s.charAt(x1--) + word; + } else + x1 = -1; + } else + x1 = -1; + + if (x2 >= 0 && x2 < s.length()) { + if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' + || s.charAt(x2) == '$') + word = word + s.charAt(x2++); + else + x2 = -1; + } else + x2 = -1; + + if (x1 < 0 && x2 < 0) + break; + if (i > 200) { + // time out! + System.err.println("Whoopsy! :P"); break; } } - return newString; - } - - /** - * Sets ErrorCheckerService and loads theme for TextAreaPainter(XQMode) - * @param ecs - * @param mode - */ - public void setECSandTheme(ErrorCheckerService ecs, ExperimentalMode mode){ - this.errorCheckerService = ecs; - loadTheme(mode); + if (Character.isDigit(word.charAt(0))) + return null; + String tooltipText = errorCheckerService.astGenerator + .getLabelForASTNode(line + errorCheckerService.mainClassOffset, word, + xLS); + + System.out.print(errorCheckerService.mainClassOffset + " MCO "); + System.out.print("|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n"); + if (tooltipText != null) + return tooltipText; + return word; } + + } + } diff --git a/pdex/src/processing/mode/experimental/XQPreprocessor.java b/pdex/src/processing/mode/experimental/XQPreprocessor.java index cc263072f..34ee2a9a2 100755 --- a/pdex/src/processing/mode/experimental/XQPreprocessor.java +++ b/pdex/src/processing/mode/experimental/XQPreprocessor.java @@ -55,7 +55,6 @@ import processing.mode.java.preproc.PdePreprocessor; public class XQPreprocessor { private ASTRewrite rewrite = null; - public int mainClassOffset = 0; private ArrayList imports; private ArrayList extraImports; @@ -76,7 +75,7 @@ public class XQPreprocessor { public String doYourThing(String source, ArrayList programImports) { this.extraImports = programImports; - source = prepareImports() + source; + //source = prepareImports() + source; Document doc = new Document(source); ASTParser parser = ASTParser.newParser(AST.JLS4); @@ -117,7 +116,6 @@ public class XQPreprocessor { } lines += 2; // System.out.println("Lines: " + lines); - mainClassOffset = lines; return doc.get(); } @@ -146,6 +144,11 @@ public class XQPreprocessor { totalImports += "\n"; return totalImports; } + + public String prepareImports(ArrayList programImports) { + this.extraImports = programImports; + return prepareImports(); + } /** * Visitor implementation that does all the substitution dirty work.