ECS + ASTGen: big offset fix

- PreprocessedSketch is now top level class
- go do declaration (ctrl+click) was fixed and is now handled via JDT
- various offset conversions were simplified and code completion now
works as before
This commit is contained in:
Jakub Valtar
2016-04-16 22:55:21 +02:00
parent 68264f228d
commit 55e955b9fb
5 changed files with 313 additions and 392 deletions

View File

@@ -57,9 +57,6 @@ import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.PlainDocument;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
@@ -75,9 +72,11 @@ 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.IBinding;
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.ParameterizedType;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.QualifiedName;
@@ -95,13 +94,10 @@ import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import processing.app.Messages;
import processing.app.SketchCode;
import processing.app.Util;
import processing.app.syntax.JEditTextArea;
import processing.app.ui.EditorStatus;
import processing.app.ui.Toolkit;
import processing.mode.java.JavaEditor;
import processing.mode.java.pdex.ErrorCheckerService.PreprocessedSketch;
import com.google.classpath.ClassPath;
import com.google.classpath.RegExpResourceFilter;
@@ -1028,122 +1024,36 @@ public class ASTGenerator {
* @param scrollOnly
* @return
*/
// TODO: nuke this in favor of NodeFinder
public ASTNode getASTNodeAt(int lineNumber, String name, int offset,
boolean scrollOnly) {
public ASTNode getASTNodeAt(int offset) {
Messages.log("* getASTNodeAt");
// Convert tab based pde line number to actual line number
int pdeLineNumber = lineNumber + errorCheckerService.mainClassOffset;
// log("----getASTNodeAt---- CU State: "
// + errorCheckerService.compilationUnitState);
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 = Util.countLines(sc.getProgram()) + 1;
pdeLineNumber += len;
}
PreprocessedSketch ps = errorCheckerService.latestResult;
int tabIndex = ps.sketch.getCodeIndex(editor.getCurrentTab());
int javaOffset = ps.tabOffsetToJavaOffset(tabIndex, offset);
ASTNode node = NodeFinder.perform(ps.compilationUnit, javaOffset, 0);
if (node == null) {
Messages.log("no node found");
return null;
}
// Find closest ASTNode to the linenumber
// log("getASTNodeAt: Node line number " + pdeLineNumber);
CompilationUnit compilationUnit =
errorCheckerService.latestResult.compilationUnit;
ASTNode lineNode = findLineOfNode(compilationUnit, pdeLineNumber, offset,
name);
// log("Node text +> " + lineNode);
ASTNode decl = null;
String nodeLabel = null;
String nameOfNode = null; // The node name which is to be scrolled to
// Obtain correspondin java code at that line, match offsets
if (lineNode != null) {
// TODO
String pdeCodeLine = ""; //errorCheckerService.getPdeCodeAtLine(editor
// .getSketch().getCurrentCodeIndex(), lineNumber);
String javaCodeLine = getJavaSourceCodeLine(pdeLineNumber);
// log(lineNumber + " Original Line num.\nPDE :" + pdeCodeLine);
// log("JAVA:" + javaCodeLine);
// log("Clicked on: " + name + " start offset: " + offset);
// Calculate expected java offset based on the pde line
OffsetMatcher ofm = new OffsetMatcher(pdeCodeLine, javaCodeLine);
int javaOffset = ofm.getJavaOffForPdeOff(offset, name.length())
+ lineNode.getStartPosition();
// log("JAVA ast offset: " + (javaOffset));
// Find the corresponding node in the AST
ASTNode simpName = dfsLookForASTNode(errorCheckerService.getLatestCU(),
name, javaOffset,
javaOffset + name.length());
// If node wasn't found in the AST, lineNode may contain something
if (simpName == null && lineNode instanceof SimpleName) {
switch (lineNode.getParent().getNodeType()) {
case ASTNode.TYPE_DECLARATION:
case ASTNode.METHOD_DECLARATION:
case ASTNode.FIELD_DECLARATION:
case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
return lineNode.getParent();
default:
break;
}
}
// SimpleName instance found, now find its declaration in code
if (simpName instanceof SimpleName) {
nameOfNode = simpName.toString();
// log(getNodeAsString(simpName));
decl = findDeclaration((SimpleName) simpName);
if (decl != null) {
// Base.loge("DECLA: " + decl.getClass().getName());
nodeLabel = getLabelIfType(decl);
//retLabelString = getNodeAsString(decl);
} else {
if (scrollOnly) {
editor.statusMessage(simpName + " is not defined in this sketch",
EditorStatus.ERROR);
}
}
// log(getNodeAsString(decl));
/*
// - findDecl3 testing
ASTNode nearestNode = findClosestNode(lineNumber,
(ASTNode) compilationUnit.types()
.get(0));
ClassMember cmem = resolveExpression3rdParty(nearestNode,
(SimpleName) simpName,
false);
if (cmem != null) {
log("CMEM-> " + cmem);
} else
log("CMEM-> null");
*/
}
}
if (decl != null && scrollOnly) {
/*
* For scrolling, we highlight just the name of the node, i.e., a
* SimpleName instance. But the declared node always points to the
* declared node itself, like TypeDecl, MethodDecl, etc. This is important
* since it contains all the properties.
*/
ASTNode simpName2 = getNodeName(decl, nameOfNode);
// TODO: highlight ASTNode (should not be here though)
}
// Return the declaration wrapped as ASTNodeWrapper
return decl;
Messages.log("found " + node.toString());
return node;
}
public static IBinding resolveBinding(ASTNode node) {
Messages.log("* resolveBinding " + node.getClass().getSimpleName());
switch (node.getNodeType()) {
case ASTNode.SIMPLE_NAME:
return ((SimpleName) node).resolveBinding();
// For now only used for SimpleNames, add more as needed
default:
return null;
}
}
/**
* Given a declaration type astnode, returns the SimpleName peroperty
* of that node.
@@ -1151,15 +1061,19 @@ public class ASTGenerator {
* @param name - The name we're looking for.
* @return SimpleName
*/
protected static ASTNode getNodeName(ASTNode node, String name){
protected static SimpleName getNodeName(ASTNode node, String name){
List<VariableDeclarationFragment> vdfs = null;
switch (node.getNodeType()) {
case ASTNode.SIMPLE_NAME:
return (SimpleName) node;
case ASTNode.TYPE_DECLARATION:
return ((TypeDeclaration) node).getName();
case ASTNode.METHOD_DECLARATION:
return ((MethodDeclaration) node).getName();
case ASTNode.SINGLE_VARIABLE_DECLARATION:
return ((SingleVariableDeclaration) node).getName();
case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
return ((VariableDeclarationFragment) node).getName();
case ASTNode.FIELD_DECLARATION:
vdfs = ((FieldDeclaration) node).fragments();
break;
@@ -1174,12 +1088,15 @@ public class ASTGenerator {
}
if (vdfs != null) {
for (VariableDeclarationFragment vdf : vdfs) {
if (vdf.getName().toString().equals(name)) {
return vdf.getName();
if (vdfs.size() == 1) {
return vdfs.get(0).getName();
} else {
for (VariableDeclarationFragment vdf : vdfs) {
if (vdf.getName().toString().equals(name)) {
return vdf.getName();
}
}
}
}
return null;
}
@@ -1318,10 +1235,10 @@ public class ASTGenerator {
return lastClickedWord;
}
public void setLastClickedWord(int lineNumber, String lastClickedWord, int offset) {
public void setLastClickedWord(int offset, String lastClickedWord) {
Messages.log("* setLastClickedWord");
this.lastClickedWord = lastClickedWord;
lastClickedWordNode = getASTNodeAt(lineNumber, lastClickedWord, offset, false);
lastClickedWordNode = getASTNodeAt(offset);
log("Last clicked node: " + lastClickedWordNode);
}
@@ -1339,11 +1256,9 @@ public class ASTGenerator {
+ (ta.getSelectionStart() - ta.getLineStartOffset(line))
+ ", "
+ (ta.getSelectionStop() - ta.getLineStartOffset(line)));
int offwhitespace = ta.getLineStartNonWhiteSpaceOffset(line);
ASTNode wnode;
if (lastClickedWord == null || lastClickedWordNode == null) {
wnode = getASTNodeAt(line + errorCheckerService.mainClassOffset, selText,
ta.getSelectionStart() - offwhitespace, false);
wnode = getASTNodeAt(ta.getSelectionStart());
}
else{
wnode = lastClickedWordNode;
@@ -1459,59 +1374,6 @@ public class ASTGenerator {
}
}
public ASTNode dfsLookForASTNode(ASTNode root, String name, int startOffset,
int endOffset) {
// log("dfsLookForASTNode() lookin for " + name + " Offsets: " + startOffset
// + "," + endOffset);
Stack<ASTNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
ASTNode node = stack.pop();
//log("Popped from stack: " + getNodeAsString(node));
for (StructuralPropertyDescriptor prop : (Iterable<StructuralPropertyDescriptor>) node.structuralPropertiesForType()) {
if (prop.isChildProperty() || prop.isSimpleProperty()) {
if (node.getStructuralProperty(prop) instanceof ASTNode) {
ASTNode temp = (ASTNode) node.getStructuralProperty(prop);
if (temp.getStartPosition() <= startOffset
&& (temp.getStartPosition() + temp.getLength()) >= endOffset) {
if (temp instanceof SimpleName) {
if (name.equals(temp.toString())) {
// log("Found simplename: " + getNodeAsString(temp));
return temp;
}
// log("Bummer, didn't match");
} else
stack.push(temp);
//log("Pushed onto stack: " + getNodeAsString(temp));
}
}
} else if (prop.isChildListProperty()) {
List<ASTNode> nodelist =
(List<ASTNode>) node.getStructuralProperty(prop);
for (ASTNode temp : nodelist) {
if (temp.getStartPosition() <= startOffset
&& (temp.getStartPosition() + temp.getLength()) >= endOffset) {
stack.push(temp);
// log("Pushed onto stack: " + getNodeAsString(temp));
if (temp instanceof SimpleName) {
if (name.equals(temp.toString())) {
// log("Found simplename: " + getNodeAsString(temp));
return temp;
}
// log("Bummer, didn't match");
} else
stack.push(temp);
//log("Pushed onto stack: " + getNodeAsString(temp));
}
}
}
}
}
// log("dfsLookForASTNode() not found " + name);
return null;
}
/*
protected SketchOutline sketchOutline;
@@ -1597,79 +1459,6 @@ public class ASTGenerator {
}
public static void printRecur(ASTNode node) {
//Base.loge("Props of " + node.getClass().getName());
for (StructuralPropertyDescriptor prop : (Iterable<StructuralPropertyDescriptor>) node
.structuralPropertiesForType()) {
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);
log(getNodeAsString(cnode));
printRecur(cnode);
}
}
} else if (prop.isChildListProperty()) {
List<ASTNode> nodelist = (List<ASTNode>) node
.getStructuralProperty(prop);
for (ASTNode cnode : nodelist) {
log(getNodeAsString(cnode));
printRecur(cnode);
}
}
}
}
protected static ASTNode findLineOfNode(ASTNode node, int lineNumber,
int offset, String name) {
if (node == null) return null;
CompilationUnit root = (CompilationUnit) node.getRoot();
// log("Inside "+getNodeAsString(node) + " | " + root.getLineNumber(node.getStartPosition()));
if (root.getLineNumber(node.getStartPosition()) == lineNumber) {
// Base.loge(3 + getNodeAsString(node) + " len " + node.getLength());
return node;
// if (offset < node.getLength())
// return node;
// else {
// Base.loge(-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) {
// Base.loge(11 + getNodeAsString(retNode));
return retNode;
}
}
}
} else if (prop.isChildListProperty()) {
List<ASTNode> nodelist = (List<ASTNode>) node
.getStructuralProperty(prop);
for (ASTNode retNode : nodelist) {
ASTNode rr = findLineOfNode(retNode, lineNumber, offset, name);
if (rr != null) {
// Base.loge(12 + getNodeAsString(rr));
return rr;
}
}
}
}
// Base.loge("-1");
return null;
}
/**
* Give this thing a {@link Name} instance - a {@link SimpleName} from the
* ASTNode for ex, and it tries its level best to locate its declaration in
@@ -2543,16 +2332,11 @@ public class ASTGenerator {
return candidates;
}
int lineNumber = line;
PreprocessedSketch ps = errorCheckerService.latestResult;
// Adjust line number for tabbed sketches
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 = Util.countLines(sc.getProgram()) + 1;
lineNumber += len;
}
}
int lineNumber = ps.tabLineToJavaLine(codeIndex, line);
// Ensure that we're not inside a comment. TODO: Binary search
@@ -2914,9 +2698,38 @@ public class ASTGenerator {
/// Editor stuff -------------------------------------------------------------
public void scrollToDeclaration(int lineNumber, String name, int offset) {
public void scrollToDeclaration(int offset, String name) {
Messages.log("* scrollToDeclaration");
getASTNodeAt(lineNumber, name, offset, true);
ASTNode node = getASTNodeAt(offset);
if (node == null) {
return;
}
PreprocessedSketch ps = errorCheckerService.latestResult;
IBinding binding = resolveBinding(node);
if (binding == null) {
Messages.log("binding not resolved");
return;
}
String key = binding.getKey();
ASTNode decl = ps.compilationUnit.findDeclaringNode(key);
if (decl == null) {
Messages.log("decl not found");
return;
}
SimpleName declName = getNodeName(decl, name);
if (declName == null) {
Messages.log("decl name not found " + decl);
return;
}
Messages.log("decl " + decl.getStartPosition() + " " + declName);
errorCheckerService.highlightJavaRange(declName.getStartPosition(), declName.getLength());
}
@@ -2925,33 +2738,6 @@ public class ASTGenerator {
}
/**
* Returns the java source code line at the given line number
* @param javaLineNumber
* @return
*/
public String getJavaSourceCodeLine(int javaLineNumber) {
Messages.log("* getJavaSourceCodeLine");
try {
PlainDocument javaSource = new PlainDocument();
javaSource.insertString(0, errorCheckerService.latestResult.preprocessedCode, null);
Element lineElement = javaSource.getDefaultRootElement()
.getElement(javaLineNumber - 1);
if (lineElement == null) {
log("Couldn't fetch jlinenum " + javaLineNumber);
return null;
}
String javaLine = javaSource.getText(lineElement.getStartOffset(),
lineElement.getEndOffset()
- lineElement.getStartOffset());
return javaLine;
} catch (BadLocationException e) {
Messages.loge(e + " in getJavaSourceCodeline() for jinenum: " + javaLineNumber);
}
return null;
}
/// GUI ----------------------------------------------------------------------

View File

@@ -37,8 +37,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -111,14 +109,6 @@ public class ErrorCheckerService {
*/
private volatile boolean running;
/**
* How many lines are present till the initial class declaration? In static
* mode, this would include imports, class declaration and setup
* declaration. In nomral mode, this would include imports, class
* declaration only. It's fate is decided inside preprocessCode()
*/
public int mainClassOffset;
/**
* ASTGenerator for operations on AST
*/
@@ -144,7 +134,7 @@ public class ErrorCheckerService {
*/
private final static long errorCheckInterval = 650;
protected volatile PreprocessedSketch latestResult = new PreprocessedSketch();
protected volatile PreprocessedSketch latestResult = PreprocessedSketch.empty();
private Thread errorCheckerThread;
private final BlockingQueue<Boolean> requestQueue = new ArrayBlockingQueue<>(1);
@@ -309,41 +299,9 @@ public class ErrorCheckerService {
};
public static class PreprocessedSketch {
Sketch sketch;
Mode mode;
String className;
CompilationUnit compilationUnit;
String[] classPathArray;
ClassPath classPath;
URLClassLoader classLoader;
int[] tabStarts;
String pdeCode;
String preprocessedCode;
SourceMapping syntaxMapping;
SourceMapping compilationMapping;
boolean hasSyntaxErrors;
boolean hasCompilationErrors;
final List<Problem> problems = new ArrayList<>();
final List<ImportStatement> programImports = new ArrayList<>();
final List<ImportStatement> coreAndDefaultImports = new ArrayList<>();
final List<ImportStatement> codeFolderImports = new ArrayList<>();
}
protected PreprocessedSketch checkCode() {
PreprocessedSketch result = new PreprocessedSketch();
PreprocessedSketch.Builder result = new PreprocessedSketch.Builder();
PreprocessedSketch prevResult = latestResult;
List<ImportStatement> coreAndDefaultImports = result.coreAndDefaultImports;
@@ -351,7 +309,7 @@ public class ErrorCheckerService {
List<ImportStatement> programImports = result.programImports;
Sketch sketch = result.sketch = editor.getSketch();
String className = result.className = sketch.getName();
String className = sketch.getName();
StringBuilder workBuffer = new StringBuilder();
@@ -438,7 +396,6 @@ public class ErrorCheckerService {
List<IProblem> syntaxProblems = Arrays.asList(syntaxCU.getProblems());
// Update result
result.mode = mode;
result.syntaxMapping = syntaxMapping;
result.compilationUnit = syntaxCU;
result.preprocessedCode = syntaxStage;
@@ -489,7 +446,6 @@ public class ErrorCheckerService {
result.classPathArray = classPathArray;
}
if (!result.hasSyntaxErrors) {
{{ // COMPILATION CHECK
@@ -520,6 +476,7 @@ public class ErrorCheckerService {
result.preprocessedCode = javaStage;
result.compilationUnit = compilationCU;
// TODO: handle error stuff *after* building PreprocessedSketch
List<Problem> mappedCompilationProblems =
mapProblems(compilationProblems, result.tabStarts, result.pdeCode,
result.compilationMapping, result.syntaxMapping);
@@ -556,7 +513,7 @@ public class ErrorCheckerService {
}}
}
return result;
return result.build();
}
@@ -1016,58 +973,12 @@ public class ErrorCheckerService {
}
protected static int mapJavaToTab(PreprocessedSketch sketch, int offset) {
int tab = Arrays.binarySearch(sketch.tabStarts, offset);
if (tab < 0) {
tab = -(tab + 1) - 1;
}
return sketch.tabStarts[tab];
}
protected static int mapJavaToProcessing(PreprocessedSketch sketch, int offset) {
SourceMapping syntaxMapping = sketch.syntaxMapping;
SourceMapping compilationMapping = sketch.compilationMapping;
if (compilationMapping != null) {
offset = compilationMapping.getInputOffset(offset);
}
if (syntaxMapping != null) {
offset = syntaxMapping.getInputOffset(offset);
}
return offset;
}
protected static int mapProcessingToJava(PreprocessedSketch sketch, int offset) {
SourceMapping syntaxMapping = sketch.syntaxMapping;
SourceMapping compilationMapping = sketch.compilationMapping;
if (syntaxMapping != null) {
offset = syntaxMapping.getOutputOffset(offset);
}
if (compilationMapping != null) {
offset = compilationMapping.getOutputOffset(offset);
}
return offset;
}
// TODO: does this belong here?
// Thread: EDT
public void scrollToErrorLine(Problem p) {
if (editor == null) return;
if (p == null) return;
// Switch to tab
editor.toFront();
editor.getSketch().setCurrentCode(p.getTabIndex());
// Highlight the code
int startOffset = p.getStartOffset();
int stopOffset = p.getStopOffset();
@@ -1075,7 +986,19 @@ public class ErrorCheckerService {
int length = editor.getTextArea().getDocumentLength();
startOffset = PApplet.constrain(startOffset, 0, length);
stopOffset = PApplet.constrain(stopOffset, 0, length);
editor.getTextArea().select(startOffset, stopOffset);
highlightTabRange(p.getTabIndex(), startOffset, stopOffset);
}
// TODO: does this belong here?
// Thread: EDT
public void highlightTabRange(int tabIndex, int startTabOffset, int stopTabOffset) {
// Switch to tab
editor.toFront();
editor.getSketch().setCurrentCode(tabIndex);
// Highlight the code
editor.getTextArea().select(startTabOffset, stopTabOffset);
// Scroll to error line
editor.getTextArea().scrollToCaret();
@@ -1083,6 +1006,27 @@ public class ErrorCheckerService {
}
public void highlightJavaRange(int startJavaOffset, int javaLength) {
PreprocessedSketch ps = latestResult;
int stopJavaOffset = startJavaOffset + javaLength;
int startPdeOffset = ps.javaOffsetToPdeOffset(startJavaOffset);
int stopPdeOffset = javaLength == 0 ?
startPdeOffset :
// Make the stop inclusive for the purpose of mapping
ps.javaOffsetToPdeOffset(stopJavaOffset - 1) + 1;
int tabIndex = ps.pdeOffsetToTabIndex(startPdeOffset);
int startTabOffset = ps.pdeOffsetToTabOffset(tabIndex, startPdeOffset);
int stopTabOffset = ps.pdeOffsetToTabOffset(tabIndex, stopPdeOffset);
EventQueue.invokeLater(() -> highlightTabRange(tabIndex, startTabOffset, stopTabOffset));
}
/**
* Checks if import statements in the sketch have changed. If they have,
* compiler classpath needs to be updated.

View File

@@ -277,7 +277,6 @@ public class JavaTextArea extends JEditTextArea {
return null;
else {
int x = xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1;
int xLS = off - getLineStartNonWhiteSpaceOffset(line);
Messages.log("x=" + x);
if (x < 0 || x >= s.length())
return null;
@@ -293,7 +292,6 @@ public class JavaTextArea extends JEditTextArea {
if (x1 >= 0 && x1 < s.length()) {
if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') {
word = s.charAt(x1--) + word;
xLS--;
} else
x1 = -1;
} else
@@ -321,7 +319,7 @@ public class JavaTextArea extends JEditTextArea {
Messages.log("Mouse click, word: " + word.trim());
ASTGenerator astGenerator = editor.getErrorChecker().getASTGenerator();
synchronized (astGenerator) {
astGenerator.setLastClickedWord(line, word, xLS);
astGenerator.setLastClickedWord(off, word);
}
return word.trim();
}
@@ -404,8 +402,7 @@ public class JavaTextArea extends JEditTextArea {
ASTGenerator astGenerator = editor.getErrorChecker().getASTGenerator();
synchronized (astGenerator) {
int lineOffset = caretLineIndex +
editor.getErrorChecker().mainClassOffset;
int lineOffset = caretLineIndex;
candidates = astGenerator.preparePredictions(phrase, lineOffset);
}

View File

@@ -175,10 +175,10 @@ public class JavaTextAreaPainter extends TextAreaPainter
if (Character.isDigit(word.charAt(0)))
return;
Messages.log(getJavaEditor().getErrorChecker().mainClassOffset + line + "|" + line + "| offset " + xLS + word + " <= \n");
Messages.log(line + "|" + line + "| offset " + xLS + word + " <= \n");
ASTGenerator astGenerator = getJavaEditor().getErrorChecker().getASTGenerator();
synchronized (astGenerator) {
astGenerator.scrollToDeclaration(line, word, xLS);
astGenerator.scrollToDeclaration(off, word);
}
}
}

View File

@@ -0,0 +1,194 @@
package processing.mode.java.pdex;
import com.google.classpath.ClassPath;
import org.eclipse.jdt.core.dom.CompilationUnit;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import processing.app.Sketch;
public class PreprocessedSketch {
public final Sketch sketch;
public final CompilationUnit compilationUnit;
public final String[] classPathArray;
public final ClassPath classPath;
public final URLClassLoader classLoader;
public final int[] tabStarts;
public final String pdeCode;
public final String preprocessedCode;
public final SourceMapping syntaxMapping;
public final SourceMapping compilationMapping;
public final boolean hasSyntaxErrors;
public final boolean hasCompilationErrors;
public final List<Problem> problems;
public final List<ImportStatement> programImports;
public final List<ImportStatement> coreAndDefaultImports;
public final List<ImportStatement> codeFolderImports;
// TODO: optimize
public static int lineToOffset(String text, int line) {
int lineOffset = 0;
for (int i = 0; i < line && lineOffset >= 0; i++) {
lineOffset = text.indexOf('\n', lineOffset+1);
}
return lineOffset + 1;
}
// TODO: optimize
public static int offsetToLine(String text, int offset) {
int line = 0;
while (offset >= 0) {
offset = text.lastIndexOf('\n', offset-1);
line++;
}
return line - 1;
}
// TODO: optimize, build lookup together with tabStarts
public int tabIndexToTabStartLine(int tabIndex) {
int pdeLineNumber = 0;
for (int i = 0; i < tabIndex; i++) {
pdeLineNumber += sketch.getCode(i).getLineCount();
}
return pdeLineNumber;
}
public int tabLineToJavaLine(int tabIndex, int tabLine) {
int tabStartLine = tabIndexToTabStartLine(tabIndex);
int pdeLine = tabStartLine + tabLine;
int pdeLineOffset = lineToOffset(pdeCode, pdeLine);
int javaLineOffset = syntaxMapping.getOutputOffset(pdeLineOffset);
if (compilationMapping != null) {
javaLineOffset = compilationMapping.getOutputOffset(javaLineOffset);
}
return offsetToLine(preprocessedCode, javaLineOffset);
}
public int tabOffsetToJavaOffset(int tabIndex, int tabOffset) {
int tabStartLine = tabIndexToTabStartLine(tabIndex);
int tabStartOffset = lineToOffset(pdeCode, tabStartLine);
int pdeOffset = tabStartOffset + tabOffset;
int javaOffset = syntaxMapping.getOutputOffset(pdeOffset);
if (compilationMapping != null) {
javaOffset = compilationMapping.getOutputOffset(javaOffset);
}
return javaOffset;
}
public int javaOffsetToPdeOffset(int javaOffset) {
int pdeOffset = javaOffset;
if (compilationMapping != null) {
pdeOffset = compilationMapping.getInputOffset(pdeOffset);
}
if (syntaxMapping != null) {
pdeOffset = syntaxMapping.getInputOffset(pdeOffset);
}
return pdeOffset;
}
public int pdeOffsetToTabIndex(int pdeOffset) {
int tab = Arrays.binarySearch(tabStarts, pdeOffset);
if (tab < 0) {
tab = -(tab + 1) - 1;
}
return tab;
}
public int pdeOffsetToTabOffset(int tabIndex, int pdeOffset) {
int tabStartOffset = tabStarts[tabIndex];
return pdeOffset - tabStartOffset;
}
/// BUILDER BUSINESS /////////////////////////////////////////////////////////
/**
* There is a lot of fields and having constructor with this many parameters
* is just not practical. Fill stuff into builder and then simply build it.
* Builder also guards against calling methods in the middle of building process.
*/
public static class Builder {
public Sketch sketch;
public CompilationUnit compilationUnit;
public String[] classPathArray;
public ClassPath classPath;
public URLClassLoader classLoader;
public int[] tabStarts = new int[0];
public String pdeCode;
public String preprocessedCode;
public SourceMapping syntaxMapping;
public SourceMapping compilationMapping;
public boolean hasSyntaxErrors;
public boolean hasCompilationErrors;
public final List<Problem> problems = new ArrayList<>();
public final List<ImportStatement> programImports = new ArrayList<>();
public final List<ImportStatement> coreAndDefaultImports = new ArrayList<>();
public final List<ImportStatement> codeFolderImports = new ArrayList<>();
public PreprocessedSketch build() {
return new PreprocessedSketch(this);
}
}
public static PreprocessedSketch empty() {
return new Builder().build();
}
private PreprocessedSketch(Builder b) {
sketch = b.sketch;
compilationUnit = b.compilationUnit;
classPathArray = b.classPathArray;
classPath = b.classPath;
classLoader = b.classLoader;
tabStarts = b.tabStarts;
pdeCode = b.pdeCode;
preprocessedCode = b.preprocessedCode;
syntaxMapping = b.syntaxMapping;
compilationMapping = b.compilationMapping;
hasSyntaxErrors = b.hasSyntaxErrors;
hasCompilationErrors = b.hasCompilationErrors;
problems = Collections.unmodifiableList(b.problems);
programImports = Collections.unmodifiableList(b.programImports);
coreAndDefaultImports = Collections.unmodifiableList(b.coreAndDefaultImports);
codeFolderImports = Collections.unmodifiableList(b.codeFolderImports);
}
}