diff --git a/java/src/processing/mode/java/JavaEditor.java b/java/src/processing/mode/java/JavaEditor.java index b319248f5..85fc6677b 100644 --- a/java/src/processing/mode/java/JavaEditor.java +++ b/java/src/processing/mode/java/JavaEditor.java @@ -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 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 problems) { + public void setProblemList(List problems) { + this.problems = problems; + boolean hasErrors = problems.stream().anyMatch(Problem::isError); + updateErrorTable(problems); errorColumn.updateErrorPoints(problems); + textarea.repaint(); + updateErrorToggle(hasErrors); + updateEditorStatus(); } - public List getErrorPoints() { - return errorColumn.getErrorPoints(); + /** + * Updates the error table in the Error Window. + */ + public void updateErrorTable(List 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 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 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()); } } diff --git a/java/src/processing/mode/java/MarkerColumn.java b/java/src/processing/mode/java/MarkerColumn.java index 9cbedfed5..61be5c76c 100644 --- a/java/src/processing/mode/java/MarkerColumn.java +++ b/java/src/processing/mode/java/MarkerColumn.java @@ -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 getErrorPoints() { - return errorPoints; - } - - public void updateErrorPoints(final List 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(); diff --git a/java/src/processing/mode/java/pdex/ASTGenerator.java b/java/src/processing/mode/java/pdex/ASTGenerator.java index 87bcc4c68..e188a56e9 100644 --- a/java/src/processing/mode/java/pdex/ASTGenerator.java +++ b/java/src/processing/mode/java/pdex/ASTGenerator.java @@ -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)); } }); } diff --git a/java/src/processing/mode/java/pdex/ErrorCheckerService.java b/java/src/processing/mode/java/pdex/ErrorCheckerService.java index 553e32728..e2b809522 100644 --- a/java/src/processing/mode/java/pdex/ErrorCheckerService.java +++ b/java/src/processing/mode/java/pdex/ErrorCheckerService.java @@ -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 errorHandlerListener = this::handleSketchErrors; + private final Consumer 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 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 problems, boolean hasErrors) { - updateErrorTable(problems); - editor.updateErrorBar(problems); - editor.getTextArea().repaint(); - editor.updateErrorToggle(hasErrors); - } - - protected String[] buildClassPath(List 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 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); } diff --git a/java/src/processing/mode/java/pdex/JavaTextAreaPainter.java b/java/src/processing/mode/java/pdex/JavaTextAreaPainter.java index e4b8bb913..1602946e3 100644 --- a/java/src/processing/mode/java/pdex/JavaTextAreaPainter.java +++ b/java/src/processing/mode/java/pdex/JavaTextAreaPainter.java @@ -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); diff --git a/java/src/processing/mode/java/pdex/LineMarker.java b/java/src/processing/mode/java/pdex/LineMarker.java index a812ec48c..89e51d50f 100644 --- a/java/src/processing/mode/java/pdex/LineMarker.java +++ b/java/src/processing/mode/java/pdex/LineMarker.java @@ -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; } diff --git a/java/src/processing/mode/java/pdex/Problem.java b/java/src/processing/mode/java/pdex/Problem.java index 89d3f4a61..8d8fac2e0 100644 --- a/java/src/processing/mode/java/pdex/Problem.java +++ b/java/src/processing/mode/java/pdex/Problem.java @@ -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;