ECS: clean up problem handling, move editor functions to JavaEditor

This commit is contained in:
Jakub Valtar
2016-04-30 19:07:08 +02:00
parent e3296c48de
commit 531a6aaaf3
7 changed files with 121 additions and 167 deletions

View File

@@ -5,6 +5,7 @@ import java.awt.event.*;
import java.beans.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -31,7 +32,6 @@ import processing.mode.java.debug.LineID;
import processing.mode.java.pdex.ASTGenerator;
import processing.mode.java.pdex.ErrorCheckerService;
import processing.mode.java.pdex.ImportStatement;
import processing.mode.java.pdex.LineMarker;
import processing.mode.java.pdex.JavaTextArea;
import processing.mode.java.pdex.Problem;
import processing.mode.java.pdex.SourceUtils;
@@ -72,6 +72,8 @@ public class JavaEditor extends Editor {
protected ErrorCheckerService errorCheckerService;
protected List<Problem> problems = Collections.emptyList();
protected JavaEditor(Base base, String path, EditorState state,
Mode mode) throws EditorException {
@@ -160,7 +162,7 @@ public class JavaEditor extends Editor {
textarea.addCaretListener(new CaretListener() {
public void caretUpdate(CaretEvent e) {
errorCheckerService.updateEditorStatus();
updateEditorStatus();
}
});
}
@@ -210,6 +212,9 @@ public class JavaEditor extends Editor {
if (errorCheckerService != null) {
if (hasJavaTabsChanged) {
errorCheckerService.handleHasJavaTabsChange(hasJavaTabs);
if (hasJavaTabs) {
setProblemList(Collections.emptyList());
}
}
int currentTabCount = sketch.getCodeCount();
@@ -2512,31 +2517,106 @@ public class JavaEditor extends Editor {
// }
public void updateErrorBar(List<Problem> problems) {
public void setProblemList(List<Problem> problems) {
this.problems = problems;
boolean hasErrors = problems.stream().anyMatch(Problem::isError);
updateErrorTable(problems);
errorColumn.updateErrorPoints(problems);
textarea.repaint();
updateErrorToggle(hasErrors);
updateEditorStatus();
}
public List<LineMarker> getErrorPoints() {
return errorColumn.getErrorPoints();
/**
* Updates the error table in the Error Window.
*/
public void updateErrorTable(List<Problem> problems) {
errorTable.clearRows();
for (Problem p : problems) {
String message = p.getMessage();
if (Preferences.getBoolean(JavaMode.SUGGEST_IMPORTS_PREF) &&
p.getImportSuggestions() != null &&
p.getImportSuggestions().length > 0) {
message += " (double-click for suggestions)";
}
errorTable.addRow(p, message,
sketch.getCode(p.getTabIndex()).getPrettyName(),
Integer.toString(p.getLineNumber() + 1));
// Added +1 because lineNumbers internally are 0-indexed
}
}
public void highlight(Problem p) {
if (p != null) {
highlight(p.getTabIndex(), p.getStartOffset(), p.getStartOffset());
}
}
public void highlight(int tabIndex, int startOffset, int stopOffset) {
// Switch to tab
toFront();
sketch.setCurrentCode(tabIndex);
// Make sure offsets are in bounds
int length = textarea.getDocumentLength();
startOffset = PApplet.constrain(startOffset, 0, length);
stopOffset = PApplet.constrain(stopOffset, 0, length);
// Highlight the code
textarea.select(startOffset, stopOffset);
// Scroll to error line
textarea.scrollToCaret();
repaint();
}
public List<Problem> getProblems() {
return problems;
}
/**
* Updates editor status bar, depending on whether the caret is on an error
* line or not
*/
public void updateEditorStatus() {
if (JavaMode.errorCheckEnabled) {
Problem problem = findError(textarea.getCaretLine());
if (problem != null) {
int type = problem.isError() ?
EditorStatus.CURSOR_LINE_ERROR : EditorStatus.CURSOR_LINE_WARNING;
statusMessage(problem.getMessage(), type);
} else {
switch (getStatusMode()) {
case EditorStatus.CURSOR_LINE_ERROR:
case EditorStatus.CURSOR_LINE_WARNING:
statusEmpty();
break;
}
}
}
}
/**
* @return the LineMarker for the first error or warning on 'line'
*/
public LineMarker findError(int line) {
List<LineMarker> errorPoints = getErrorPoints();
public Problem findError(int line) {
JavaTextArea textArea = getJavaTextArea();
int currentTab = getSketch().getCurrentCodeIndex();
for (LineMarker emarker : errorPoints) {
if (emarker.getProblem().getTabIndex() != currentTab) continue;
Problem p = emarker.getProblem();
for (Problem p : problems) {
if (p.getTabIndex() != currentTab) continue;
int pStartLine = p.getLineNumber();
int pEndOffset = p.getStopOffset();
int pEndLine = textArea.getLineOfOffset(pEndOffset);
if (line >= pStartLine && line <= pEndLine) {
return emarker;
return p;
}
}
return null;
@@ -2573,8 +2653,7 @@ public class JavaEditor extends Editor {
public void errorTableClick(Object item) {
Problem p = (Problem) item;
errorCheckerService.scrollToErrorLine(p);
highlight((Problem) item);
}
@@ -2598,6 +2677,8 @@ public class JavaEditor extends Editor {
// showImportSuggestion(temp, evt.getXOnScreen(), evt.getYOnScreen() - 3 * getFont().getSize());
Point mouse = MouseInfo.getPointerInfo().getLocation();
showImportSuggestion(temp, mouse.x, mouse.y);
} else {
errorTableClick(item);
}
}
@@ -2759,6 +2840,7 @@ public class JavaEditor extends Editor {
Messages.log("Applying prefs");
// trigger it once to refresh UI
errorCheckerService.handlePreferencesChange();
setProblemList(Collections.emptyList());
}
}

View File

@@ -91,6 +91,7 @@ public class MarkerColumn extends JPanel {
}
@Override
public void paintComponent(Graphics g) {
g.drawImage(editor.getJavaTextArea().getGutterGradient(),
0, 0, getWidth(), getHeight(), this);
@@ -109,17 +110,11 @@ public class MarkerColumn extends JPanel {
}
public List<LineMarker> getErrorPoints() {
return errorPoints;
}
public void updateErrorPoints(final List<Problem> problems) {
errorPoints = problems.stream()
.map(problem -> new LineMarker(problem, problem.isError()))
.map(LineMarker::new)
.collect(Collectors.toList());
repaint();
editor.getErrorChecker().updateEditorStatus();
}
@@ -128,7 +123,7 @@ public class MarkerColumn extends JPanel {
try {
LineMarker m = findClosestMarker(y);
if (m != null) {
editor.getErrorChecker().scrollToErrorLine(m.getProblem());
editor.highlight(m.getProblem());
}
} catch (Exception ex) {
ex.printStackTrace();

View File

@@ -2583,12 +2583,20 @@ public class ASTGenerator {
handleShowUsage(ps, binding);
} else {
Messages.log("found declaration, offset " + decl.getStartPosition() + ", name: " + declName);
ecs.highlightNode(ps, declName);
highlightNode(ps, declName);
}
});
}
public void highlightNode(PreprocessedSketch ps, ASTNode node) {
SketchInterval si = ps.mapJavaToSketch(node);
EventQueue.invokeLater(() -> {
editor.highlight(si.tabIndex, si.startTabOffset, si.stopTabOffset);
});
}
/// GUI ----------------------------------------------------------------------
@@ -2760,9 +2768,7 @@ public class ASTGenerator {
if (tnode.getUserObject() instanceof ShowUsageTreeNode) {
ShowUsageTreeNode node = (ShowUsageTreeNode) tnode.getUserObject();
astGen.ecs.highlightTabRange(node.tabIndex,
node.startTabOffset,
node.stopTabOffset);
editor.highlight(node.tabIndex, node.startTabOffset, node.stopTabOffset);
}
});
}
@@ -2963,7 +2969,7 @@ public class ASTGenerator {
if (tnode.getUserObject() instanceof ASTNode) {
ASTNode node = (ASTNode) tnode.getUserObject();
astGen.ecs.acceptWhenDone(ps1 -> astGen.ecs.highlightNode(ps1, node));
astGen.ecs.acceptWhenDone(ps1 -> astGen.highlightNode(ps1, node));
}
});
}

View File

@@ -57,7 +57,6 @@ import javax.swing.text.Document;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.IProblem;
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.CompilationUnit;
@@ -68,9 +67,6 @@ import processing.app.Sketch;
import processing.app.SketchCode;
import processing.app.SketchException;
import processing.app.Util;
import processing.app.ui.EditorStatus;
import processing.app.ui.ErrorTable;
import processing.core.PApplet;
import processing.data.IntList;
import processing.data.StringList;
import processing.mode.java.JavaEditor;
@@ -130,7 +126,7 @@ public class ErrorCheckerService {
complete(null); // initialization block
}};
private final Consumer<PreprocessedSketch> errorHandlerListener = this::handleSketchErrors;
private final Consumer<PreprocessedSketch> errorHandlerListener = this::handleSketchProblems;
private volatile boolean isEnabled = true;
private volatile boolean isContinuousCheckEnabled = true;
@@ -466,7 +462,7 @@ public class ErrorCheckerService {
}
private void handleSketchErrors(PreprocessedSketch ps) {
private void handleSketchProblems(PreprocessedSketch ps) {
// Process problems
final List<Problem> problems = ps.problems.stream()
// Filter Warnings if they are not enabled
@@ -519,9 +515,6 @@ public class ErrorCheckerService {
}
}
final boolean hasErrors = ps.hasSyntaxErrors ||
ps.hasCompilationErrors;
if (scheduledUiUpdate != null) {
scheduledUiUpdate.cancel(true);
}
@@ -531,7 +524,7 @@ public class ErrorCheckerService {
if (nextUiUpdate > 0 && System.currentTimeMillis() >= nextUiUpdate) {
EventQueue.invokeLater(() -> {
if (isContinuousCheckEnabled) {
setProblemList(problems, hasErrors);
editor.setProblemList(problems);
}
});
}
@@ -541,14 +534,6 @@ public class ErrorCheckerService {
}
protected void setProblemList(List<Problem> problems, boolean hasErrors) {
updateErrorTable(problems);
editor.updateErrorBar(problems);
editor.getTextArea().repaint();
editor.updateErrorToggle(hasErrors);
}
protected String[] buildClassPath(List<ImportStatement> neededImports) {
JavaMode mode = (JavaMode) editor.getMode();
Sketch sketch = editor.getSketch();
@@ -768,110 +753,6 @@ public class ErrorCheckerService {
}
/**
* Updates the error table in the Error Window.
*/
protected void updateErrorTable(List<Problem> problems) {
try {
ErrorTable table = editor.getErrorTable();
table.clearRows();
Sketch sketch = editor.getSketch();
for (Problem p : problems) {
String message = p.getMessage();
if (Preferences.getBoolean(JavaMode.SUGGEST_IMPORTS_PREF) &&
p.getImportSuggestions() != null &&
p.getImportSuggestions().length > 0) {
message += " (double-click for suggestions)";
}
table.addRow(p, message,
sketch.getCode(p.getTabIndex()).getPrettyName(),
Integer.toString(p.getLineNumber() + 1));
// Added +1 because lineNumbers internally are 0-indexed
}
} catch (Exception e) {
Messages.loge("Exception at updateErrorTable()", e);
e.printStackTrace();
}
}
/**
* Updates editor status bar, depending on whether the caret is on an error
* line or not
*/
public void updateEditorStatus() {
// if (editor.getStatusMode() == EditorStatus.EDIT) return;
// editor.statusNotice("Position: " +
// editor.getTextArea().getCaretLine());
if (isContinuousCheckEnabled) {
LineMarker errorMarker = editor.findError(editor.getTextArea().getCaretLine());
if (errorMarker != null) {
if (errorMarker.getType() == LineMarker.WARNING) {
editor.statusMessage(errorMarker.getProblem().getMessage(),
EditorStatus.CURSOR_LINE_WARNING);
} else {
editor.statusMessage(errorMarker.getProblem().getMessage(),
EditorStatus.CURSOR_LINE_ERROR);
}
} else {
switch (editor.getStatusMode()) {
case EditorStatus.CURSOR_LINE_ERROR:
case EditorStatus.CURSOR_LINE_WARNING:
editor.statusEmpty();
break;
}
}
}
// // This line isn't an error line anymore, so probably just clear it
// if (editor.statusMessageType == JavaEditor.STATUS_COMPILER_ERR) {
// editor.statusEmpty();
// return;
// }
}
// TODO: does this belong here?
// Thread: EDT
public void scrollToErrorLine(Problem p) {
if (p == null) return;
highlightTabRange(p.getTabIndex(), p.getStartOffset(), p.getStopOffset());
}
// TODO: does this belong here?
// Thread: EDT
public void highlightTabRange(int tabIndex, int startTabOffset, int stopTabOffset) {
if (editor == null) return;
// Switch to tab
editor.toFront();
editor.getSketch().setCurrentCode(tabIndex);
// Make sure offsets are in bounds
int length = editor.getTextArea().getDocumentLength();
startTabOffset = PApplet.constrain(startTabOffset, 0, length);
stopTabOffset = PApplet.constrain(stopTabOffset, 0, length);
// Highlight the code
editor.getTextArea().select(startTabOffset, stopTabOffset);
// Scroll to error line
editor.getTextArea().scrollToCaret();
editor.repaint();
}
public void highlightNode(PreprocessedSketch ps, ASTNode node) {
SketchInterval si = ps.mapJavaToSketch(node);
EventQueue.invokeLater(() -> {
highlightTabRange(si.tabIndex, si.startTabOffset, si.stopTabOffset);
});
}
/**
* Checks if import statements in the sketch have changed. If they have,
* compiler classpath needs to be updated.
@@ -899,7 +780,6 @@ public class ErrorCheckerService {
notifySketchChanged();
} else {
Messages.log(editor.getSketch().getName() + " Error Checker disabled.");
setProblemList(Collections.emptyList(), false);
}
}
@@ -910,7 +790,6 @@ public class ErrorCheckerService {
notifySketchChanged();
} else {
preprocessingTask.cancel(false);
setProblemList(Collections.emptyList(), false);
if (astGenerator.getGui().showUsageBinding != null) {
astGenerator.getGui().showUsageWindow.setVisible(false);
}

View File

@@ -300,10 +300,8 @@ public class JavaTextAreaPainter extends TextAreaPainter
* @param x
*/
protected void paintErrorLine(Graphics gfx, int line, int x) {
LineMarker marker = getJavaEditor().findError(line);
if (marker != null) {
Problem problem = marker.getProblem();
Problem problem = getJavaEditor().findError(line);
if (problem != null) {
int startOffset = problem.getStartOffset();
int stopOffset = problem.getStopOffset();
@@ -347,7 +345,7 @@ public class JavaTextAreaPainter extends TextAreaPainter
x2 += Editor.LEFT_GUTTER;
gfx.setColor(errorUnderlineColor);
if (marker.getType() == LineMarker.WARNING) {
if (problem.isWarning()) {
gfx.setColor(warningUnderlineColor);
}
paintSquiggle(gfx, y1, x1, x2);
@@ -388,10 +386,8 @@ public class JavaTextAreaPainter extends TextAreaPainter
public String getToolTipText(MouseEvent evt) {
int line = evt.getY() / getFontMetrics().getHeight() + textArea.getFirstLine();
if (line >= 0 || line < textArea.getLineCount()) {
LineMarker marker = getJavaEditor().findError(line);
if (marker != null) {
Problem problem = marker.getProblem();
Problem problem = getJavaEditor().findError(line);
if (problem != null) {
int lineStart = textArea.getLineStartOffset(line);
int lineEnd = textArea.getLineStopOffset(line);

View File

@@ -41,9 +41,9 @@ public class LineMarker {
private Problem problem;
public LineMarker(Problem problem, boolean error) {
public LineMarker(Problem problem) {
this.problem = problem;
this.type = error ? ERROR : WARNING;
this.type = problem.isError() ? ERROR : WARNING;
}

View File

@@ -157,10 +157,7 @@ public class Problem implements ErrorTable.Entry {
importSuggestions = a;
}
private static Pattern pattern;
private static Matcher matcher;
private static final String tokenRegExp = "\\b token\\b";
private static final Pattern tokenRegExp = Pattern.compile("\\b token\\b");
public static String process(IProblem problem) {
return process(problem.getMessage());
@@ -178,8 +175,7 @@ public class Problem implements ErrorTable.Entry {
// 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);
Matcher matcher = tokenRegExp.matcher(message);
message = matcher.replaceAll("");
return message;